From b8defa47abec560b90c78400ecace7b1abfb2c99 Mon Sep 17 00:00:00 2001
From: Mrx <18278715334@163.com>
Date: Sat, 28 Feb 2026 15:43:14 +0800
Subject: [PATCH] f
---
public/seo-templates/agent.html | 120 +++++++
public/seo-templates/example.html | 120 +++++++
public/seo-templates/help-guide.html | 120 +++++++
public/seo-templates/help.html | 120 +++++++
public/seo-templates/index.html | 120 +++++++
.../inquire-backgroundcheck.html | 120 +++++++
public/seo-templates/inquire-companyinfo.html | 120 +++++++
public/seo-templates/inquire-homeservice.html | 120 +++++++
public/seo-templates/inquire-marriage.html | 120 +++++++
.../seo-templates/inquire-personalData.html | 120 +++++++
.../inquire-preloanbackgroundcheck.html | 120 +++++++
public/seo-templates/service.html | 120 +++++++
server/README-SEO.md | 327 ++++++++++++++++++
server/crawler-detector.js | 170 +++++++++
server/generate-seo-templates.cjs | 255 ++++++++++++++
server/middleware.js | 176 ++++++++++
server/nginx-seo-location-替换片段.conf | 30 ++
server/nginx-www.xingfucha.cn.conf | 148 ++++++++
server/package.json | 28 ++
server/server-example-express.js | 36 ++
server/test-crawler-detection.js | 112 ++++++
server/test-seo.js | 176 ++++++++++
server/如何检测.md | 191 ++++++++++
server/宝塔Nginx-SEO部署说明.md | 57 +++
src/components/BindPhoneDialog.vue | 42 ++-
src/components/LoginDialog.vue | 65 ++--
src/components/RealNameAuthDialog.vue | 26 +-
src/composables/useSEO.js | 6 +-
vite.config.js | 4 +-
29 files changed, 3216 insertions(+), 73 deletions(-)
create mode 100644 public/seo-templates/agent.html
create mode 100644 public/seo-templates/example.html
create mode 100644 public/seo-templates/help-guide.html
create mode 100644 public/seo-templates/help.html
create mode 100644 public/seo-templates/index.html
create mode 100644 public/seo-templates/inquire-backgroundcheck.html
create mode 100644 public/seo-templates/inquire-companyinfo.html
create mode 100644 public/seo-templates/inquire-homeservice.html
create mode 100644 public/seo-templates/inquire-marriage.html
create mode 100644 public/seo-templates/inquire-personalData.html
create mode 100644 public/seo-templates/inquire-preloanbackgroundcheck.html
create mode 100644 public/seo-templates/service.html
create mode 100644 server/README-SEO.md
create mode 100644 server/crawler-detector.js
create mode 100644 server/generate-seo-templates.cjs
create mode 100644 server/middleware.js
create mode 100644 server/nginx-seo-location-替换片段.conf
create mode 100644 server/nginx-www.xingfucha.cn.conf
create mode 100644 server/package.json
create mode 100644 server/server-example-express.js
create mode 100644 server/test-crawler-detection.js
create mode 100644 server/test-seo.js
create mode 100644 server/如何检测.md
create mode 100644 server/宝塔Nginx-SEO部署说明.md
diff --git a/public/seo-templates/agent.html b/public/seo-templates/agent.html
new file mode 100644
index 0000000..cdb25f4
--- /dev/null
+++ b/public/seo-templates/agent.html
@@ -0,0 +1,120 @@
+
+
+
+
+
幸福查代理 - 免费开通代理权限 | 大数据风险报告代理
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/example.html b/public/seo-templates/example.html
new file mode 100644
index 0000000..845bdf7
--- /dev/null
+++ b/public/seo-templates/example.html
@@ -0,0 +1,120 @@
+
+
+
+
+
示例报告 - 幸福查报告展示 | 大数据风险报告样例
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/help-guide.html b/public/seo-templates/help-guide.html
new file mode 100644
index 0000000..8a5fef3
--- /dev/null
+++ b/public/seo-templates/help-guide.html
@@ -0,0 +1,120 @@
+
+
+
+
+
使用指南 - 幸福查操作教程 | 功能说明
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/help.html b/public/seo-templates/help.html
new file mode 100644
index 0000000..0b14342
--- /dev/null
+++ b/public/seo-templates/help.html
@@ -0,0 +1,120 @@
+
+
+
+
+
幸福查帮助中心_合作伙伴操作指南_业务规则说明
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查官方服务支持中心。提供全方位的平台使用指引,涵盖合作伙伴注册流程、业务权益说明、成本核算规则及数据系统操作教程。助您快速掌握平台功能,高效开展服务。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/index.html b/public/seo-templates/index.html
new file mode 100644
index 0000000..07f234b
--- /dev/null
+++ b/public/seo-templates/index.html
@@ -0,0 +1,120 @@
+
+
+
+
+
幸福查官网_家庭生活安全评估_个人履约与情感互信平台
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查是您的智慧家庭安全管家。专注家政用工筛查与家庭财务健康。全方位核验保姆、月嫂、护工的司法背景与失信记录,同时提供个人经济履约分析。把好家庭进门关,守护家人安宁。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/inquire-backgroundcheck.html b/public/seo-templates/inquire-backgroundcheck.html
new file mode 100644
index 0000000..9644f45
--- /dev/null
+++ b/public/seo-templates/inquire-backgroundcheck.html
@@ -0,0 +1,120 @@
+
+
+
+
+
职业背景真实性核实_个人履约与职场信用分析_幸福查
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查针对求职与用工场景,提供客观的职业背景参考。核实学历背景、职业履历一致性及潜在的竞业限制风险。降低职场信任成本,助力构建诚实守信的职业发展环境。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/inquire-companyinfo.html b/public/seo-templates/inquire-companyinfo.html
new file mode 100644
index 0000000..a5537ac
--- /dev/null
+++ b/public/seo-templates/inquire-companyinfo.html
@@ -0,0 +1,120 @@
+
+
+
+
+
家庭经营性资产风险评估_企业工商信用透视_幸福查
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查深度透视家庭经营实体的工商信用状况。评估维度覆盖企业行政处罚、司法被执行信息及经营异常名录。客观评估商业合作伙伴实力,有效规避家庭资产的连带责任风险与合同陷阱。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/inquire-homeservice.html b/public/seo-templates/inquire-homeservice.html
new file mode 100644
index 0000000..ebdf74d
--- /dev/null
+++ b/public/seo-templates/inquire-homeservice.html
@@ -0,0 +1,120 @@
+
+
+
+
+
家政人员背景核验_家庭用工司法安全评估_幸福查
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查专注家庭服务场景的安全用工工具。支持对保姆、月嫂及护工进行身份信息一致性核实与过往涉诉历史分析。科学识别服务人员的潜在风险标签,保障老人与儿童的居家生活安宁。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/inquire-marriage.html b/public/seo-templates/inquire-marriage.html
new file mode 100644
index 0000000..d6c1d90
--- /dev/null
+++ b/public/seo-templates/inquire-marriage.html
@@ -0,0 +1,120 @@
+
+
+
+
+
婚前背景综合了解_涉婚风险筛查_情感互信报告_幸福查
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查婚恋评估系统致力于维护家庭情感基石。深度评估对象的涉婚法律诉讼、失信被执行记录及社会不良标签。消除交往中的信息不对称,辅助构建透明、坦诚、安全的婚姻关系。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/inquire-personalData.html b/public/seo-templates/inquire-personalData.html
new file mode 100644
index 0000000..1e78ae3
--- /dev/null
+++ b/public/seo-templates/inquire-personalData.html
@@ -0,0 +1,120 @@
+
+
+
+
+
个人生活信用健康度_家庭经济履约画像_综合风险分析_幸福查
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查个人生活信用系统提供客观的健康指数分析。核心功能涵盖经济履约记录监测、生活消费稳定性预警及个人资质评分。通过多维数据排查潜在的信用盲点,辅助建立稳健的家庭财务档案。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/inquire-preloanbackgroundcheck.html b/public/seo-templates/inquire-preloanbackgroundcheck.html
new file mode 100644
index 0000000..be80127
--- /dev/null
+++ b/public/seo-templates/inquire-preloanbackgroundcheck.html
@@ -0,0 +1,120 @@
+
+
+
+
+
家庭财务健康度分析_个人经济履约压力检测_资金管理参考_幸福查
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查基于大数据算法对个人近期经济行为进行多维分析。精准检测资金流转稳定性、履约历史详情及生活消费压力指数。辅助用户掌握自身财务状况,科学规划家庭资金收支平衡度,提升抗风险能力。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/service.html b/public/seo-templates/service.html
new file mode 100644
index 0000000..290bf58
--- /dev/null
+++ b/public/seo-templates/service.html
@@ -0,0 +1,120 @@
+
+
+
+
+
客服中心 - 幸福查在线客服 | 技术支持
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
幸福查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/README-SEO.md b/server/README-SEO.md
new file mode 100644
index 0000000..6d5803c
--- /dev/null
+++ b/server/README-SEO.md
@@ -0,0 +1,327 @@
+# SPA SEO 优化解决方案
+
+## 📋 方案概述
+
+针对SPA应用SEO问题,采用**爬虫检测 + 静态HTML回退**方案:
+
+1. **爬虫检测**:识别搜索引擎爬虫(百度、Google、必应、搜狗等)
+2. **静态HTML**:为爬虫提供预渲染的HTML模板,包含完整的TDK信息
+3. **正常用户**:继续使用SPA应用,体验不受影响
+
+## 🏗️ 项目结构
+
+```
+server/
+├── crawler-detector.js # 爬虫检测模块
+├── middleware.js # SEO中间件(Express/Koa)
+├── generate-seo-templates.js # SEO模板生成器
+├── server-example-express.js # Express服务器示例
+├── nginx-seo.conf # Nginx配置示例
+└── README-SEO.md # 本文档
+
+public/
+└── seo-templates/ # SEO静态模板目录
+ ├── index.html # 首页模板
+ ├── agent.html # 代理页模板
+ ├── help.html # 帮助中心模板
+ ├── inquire-personalData.html # 个人查询模板
+ └── ... # 其他页面模板
+```
+
+## 🚀 快速开始
+
+### 步骤1:生成SEO模板
+
+```bash
+cd server
+node generate-seo-templates.js
+```
+
+这会在 `public/seo-templates/` 目录下生成所有页面的静态HTML模板。
+
+### 步骤2:集成到你的服务器
+
+#### 选项A:使用Express服务器
+
+```javascript
+const express = require('express')
+const SEOMiddleware = require('./server/middleware')
+
+const app = express()
+
+// 初始化SEO中间件
+const seoMiddleware = new SEOMiddleware({
+ templateDir: path.join(__dirname, 'public/seo-templates'),
+ debug: true // 开发环境开启调试日志
+})
+
+// 应用SEO中间件(必须在静态文件服务之前)
+app.use(seoMiddleware.express())
+
+// 静态文件服务
+app.use(express.static(path.join(__dirname, 'dist')))
+
+// SPA路由处理
+app.get('*', (req, res) => {
+ res.sendFile(path.join(__dirname, 'dist/index.html'))
+})
+```
+
+#### 选项B:使用Nginx
+
+```bash
+# 复制nginx配置文件
+cp server/nginx-seo.conf /etc/nginx/sites-available/xingfucha
+
+# 修改配置中的路径
+nano /etc/nginx/sites-available/xingfucha
+
+# 启用站点
+ln -s /etc/nginx/sites-available/xingfucha /etc/nginx/sites-enabled/
+
+# 重启Nginx
+nginx -t && systemctl restart nginx
+```
+
+#### 选项C:使用Koa
+
+```javascript
+const Koa = require('koa')
+const serve = require('koa-static')
+const SEOMiddleware = require('./server/middleware')
+
+const app = new Koa()
+
+// 应用SEO中间件
+const seoMiddleware = new SEOMiddleware({
+ templateDir: path.join(__dirname, 'public/seo-templates'),
+ debug: true
+})
+
+app.use(seoMiddleware.koa())
+
+// 静态文件服务
+app.use(serve(path.join(__dirname, 'dist')))
+
+app.listen(3000)
+```
+
+### 步骤3:测试爬虫检测
+
+```bash
+# 模拟百度爬虫
+curl -A "Baiduspider" http://localhost:3000/
+
+# 模拟Google爬虫
+curl -A "Googlebot/2.1" http://localhost:3000/
+
+# 模拟普通用户
+curl http://localhost:3000/
+```
+
+## 🔧 配置说明
+
+### 爬虫检测器配置
+
+`crawler-detector.js` 包含以下爬虫识别:
+
+- **中文搜索引擎**:百度、360、搜狗、必应、有道、搜搜、头条搜索
+- **国际搜索引擎**:Google、Bing、Yahoo
+- **社交媒体爬虫**:Facebook、Twitter、LinkedIn、WhatsApp等
+
+你可以根据需要添加或修改爬虫模式:
+
+```javascript
+// 在crawler-detector.js中添加新的爬虫模式
+this.crawlerPatterns.push('your-custom-bot')
+```
+
+### 路由到模板映射
+
+在 `middleware.js` 中配置路由与模板的对应关系:
+
+```javascript
+this.routeTemplateMap = {
+ '/': 'index.html',
+ '/agent': 'agent.html',
+ // 添加新的路由映射
+ '/new-route': 'new-template.html'
+}
+```
+
+### 模板生成配置
+
+在 `generate-seo-templates.js` 中配置每个页面的SEO信息:
+
+```javascript
+const pageSEOConfigs = {
+ 'new-template.html': {
+ title: '页面标题',
+ description: '页面描述',
+ keywords: '关键词1,关键词2,关键词3',
+ url: 'https://www.xingfucha.cn/new-route'
+ }
+}
+```
+
+## 📝 自定义模板
+
+### 修改模板样式
+
+编辑 `generate-seo-templates.js` 中的 `generateHTMLTemplate` 函数:
+
+```javascript
+function generateHTMLTemplate(config) {
+ return `
+
+
+
+
+
+
+
+
+ `
+}
+```
+
+### 添加结构化数据
+
+模板已包含基本的结构化数据(JSON-LD格式),如需扩展:
+
+```javascript
+const structuredData = {
+ "@context": "https://schema.org",
+ "@type": "WebPage",
+ // 添加更多字段
+ "breadcrumb": {
+ "@type": "BreadcrumbList",
+ "itemListElement": [...]
+ }
+}
+```
+
+## 🧪 验证SEO效果
+
+### 使用在线工具
+
+1. **百度资源平台**:https://ziyuan.baidu.com/
+2. **Google Search Console**:https://search.google.com/search-console
+3. **必应网站管理员工具**:https://www.bing.com/webmasters
+
+### 使用命令行工具
+
+```bash
+# 查看网页源代码
+curl -A "Baiduspider" http://www.xingfucha.cn/ | grep -o '
+
${title}
+
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
+
${description}
+
+
+
+ 关于幸福查
+ 幸福查是专业的家庭生活安全评估平台,提供全方位的风险查询服务。我们的核心使命是帮助用户建立安全、可信赖的生活环境。
+
+
+
+ 核心服务
+
+ - 个人生活信用健康度评估
+ - 家庭经营性资产风险评估
+ - 家庭财务健康度分析
+ - 婚前背景综合了解
+ - 职业背景真实性核实
+ - 家政人员背景核验
+
+
+
+
+ 为什么选择幸福查
+ 幸福查依托大数据技术,为用户提供准确、及时的风险评估报告,帮助您做出明智决策。
+
+
+
+
+
+`
+}
+
+/**
+ * 主函数
+ */
+function main() {
+ const outputDir = path.join(__dirname, '../public/seo-templates')
+
+ // 创建输出目录
+ if (!fs.existsSync(outputDir)) {
+ fs.mkdirSync(outputDir, { recursive: true })
+ console.log(`✓ 创建模板目录: ${outputDir}`)
+ }
+
+ // 生成所有模板文件
+ let successCount = 0
+ Object.entries(pageSEOConfigs).forEach(([filename, config]) => {
+ const htmlContent = generateHTMLTemplate(config)
+ const filePath = path.join(outputDir, filename)
+
+ fs.writeFileSync(filePath, htmlContent, 'utf-8')
+ console.log(`✓ 生成模板: ${filename}`)
+ successCount++
+ })
+
+ console.log(`\n✓ 成功生成 ${successCount} 个SEO模板文件`)
+ console.log(`📁 模板目录: ${outputDir}`)
+}
+
+// 执行生成
+main()
diff --git a/server/middleware.js b/server/middleware.js
new file mode 100644
index 0000000..9170e1c
--- /dev/null
+++ b/server/middleware.js
@@ -0,0 +1,176 @@
+/**
+ * SEO中间件
+ * 用于在Node.js服务器中检测爬虫并返回静态HTML
+ */
+
+const fs = require('fs')
+const path = require('path')
+const CrawlerDetector = require('./crawler-detector')
+
+class SEOMiddleware {
+ constructor(options = {}) {
+ this.detector = new CrawlerDetector()
+ this.templateDir = options.templateDir || path.join(__dirname, '../public/seo-templates')
+ this.defaultTemplate = options.defaultTemplate || 'index.html'
+ this.fallbackToSPA = options.fallbackToSPA !== false
+ this.debug = options.debug || false
+
+ // 路由到模板的映射
+ this.routeTemplateMap = {
+ '/': 'index.html',
+ '/agent': 'agent.html',
+ '/help': 'help.html',
+ '/help/guide': 'help-guide.html',
+ '/example': 'example.html',
+ '/service': 'service.html',
+ '/inquire/personalData': 'inquire-personalData.html',
+ '/inquire/companyinfo': 'inquire-companyinfo.html',
+ '/inquire/preloanbackgroundcheck': 'inquire-preloanbackgroundcheck.html',
+ '/inquire/marriage': 'inquire-marriage.html',
+ '/inquire/backgroundcheck': 'inquire-backgroundcheck.html',
+ '/inquire/homeservice': 'inquire-homeservice.html'
+ }
+
+ // 初始化模板缓存
+ this.templateCache = new Map()
+ this.cacheTemplates()
+ }
+
+ /**
+ * 缓存所有模板文件
+ */
+ cacheTemplates() {
+ try {
+ if (!fs.existsSync(this.templateDir)) {
+ console.warn(`[SEOMiddleware] 模板目录不存在: ${this.templateDir}`)
+ return
+ }
+
+ const files = fs.readdirSync(this.templateDir)
+ files.forEach(file => {
+ const filePath = path.join(this.templateDir, file)
+ if (fs.statSync(filePath).isFile()) {
+ this.templateCache.set(file, fs.readFileSync(filePath, 'utf-8'))
+ if (this.debug) {
+ console.log(`[SEOMiddleware] 已缓存模板: ${file}`)
+ }
+ }
+ })
+
+ console.log(`[SEOMiddleware] 已缓存 ${this.templateCache.size} 个模板文件`)
+ } catch (error) {
+ console.error('[SEOMiddleware] 缓存模板失败:', error)
+ }
+ }
+
+ /**
+ * 获取对应的模板文件名
+ * @param {String} path - 请求路径
+ * @returns {String} 模板文件名
+ */
+ getTemplatePath(requestPath) {
+ // 完全匹配
+ if (this.routeTemplateMap[requestPath]) {
+ return this.routeTemplateMap[requestPath]
+ }
+
+ // 模糊匹配(处理动态路由)
+ const matchedKey = Object.keys(this.routeTemplateMap).find(route => {
+ return requestPath.startsWith(route)
+ })
+
+ return matchedKey ? this.routeTemplateMap[matchedKey] : this.defaultTemplate
+ }
+
+ /**
+ * 获取模板内容
+ * @param {String} templateName - 模板文件名
+ * @returns {String|null} 模板内容
+ */
+ getTemplate(templateName) {
+ // 首先尝试缓存
+ let content = this.templateCache.get(templateName)
+
+ // 如果缓存中没有,尝试从磁盘读取
+ if (!content) {
+ try {
+ const filePath = path.join(this.templateDir, templateName)
+ if (fs.existsSync(filePath)) {
+ content = fs.readFileSync(filePath, 'utf-8')
+ this.templateCache.set(templateName, content)
+ }
+ } catch (error) {
+ console.error(`[SEOMiddleware] 读取模板失败: ${templateName}`, error)
+ }
+ }
+
+ return content || null
+ }
+
+ /**
+ * Express中间件
+ */
+ express() {
+ return (req, res, next) => {
+ // 检测是否为爬虫
+ if (this.detector.isCrawler(req)) {
+ const templateName = this.getTemplatePath(req.path)
+ const template = this.getTemplate(templateName)
+
+ if (template) {
+ // 设置响应头
+ res.setHeader('Content-Type', 'text/html; charset=utf-8')
+ res.setHeader('X-SEOMiddleware', 'prerendered')
+
+ // 返回静态HTML
+ if (this.debug) {
+ console.log(`[SEOMiddleware] 返回SEO模板: ${templateName} for ${req.path}`)
+ }
+
+ return res.send(template)
+ }
+ }
+
+ // 不是爬虫或模板不存在,继续处理SPA
+ next()
+ }
+ }
+
+ /**
+ * Koa中间件
+ */
+ koa() {
+ return async (ctx, next) => {
+ // 检测是否为爬虫
+ if (this.detector.isCrawler(ctx.req)) {
+ const templateName = this.getTemplatePath(ctx.path)
+ const template = this.getTemplate(templateName)
+
+ if (template) {
+ ctx.type = 'text/html; charset=utf-8'
+ ctx.set('X-SEOMiddleware', 'prerendered')
+
+ if (this.debug) {
+ console.log(`[SEOMiddleware] 返回SEO模板: ${templateName} for ${ctx.path}`)
+ }
+
+ ctx.body = template
+ return
+ }
+ }
+
+ await next()
+ }
+ }
+
+ /**
+ * 重新加载模板缓存
+ */
+ reloadCache() {
+ this.templateCache.clear()
+ this.cacheTemplates()
+ console.log('[SEOMiddleware] 模板缓存已重新加载')
+ }
+}
+
+module.exports = SEOMiddleware
diff --git a/server/nginx-seo-location-替换片段.conf b/server/nginx-seo-location-替换片段.conf
new file mode 100644
index 0000000..553b0db
--- /dev/null
+++ b/server/nginx-seo-location-替换片段.conf
@@ -0,0 +1,30 @@
+# ========== 在服务器上替换 SEO 的 location 用这一段 ==========
+#
+# 步骤:
+# 1. 宝塔 → 网站 → 找到 www.xingfucha.cn → 设置 → 配置文件
+# 2. 在配置文件里搜索:__seo__ 或 seo-templates
+# 3. 删掉旧的 SEO location 块,改成下面「新写法」两段(seo-templates 段 + location / 里的 if+rewrite)
+# 4. 保存 → SSH 执行 nginx -t && nginx -s reload
+#
+# ---------- 新写法(用 root,不依赖 alias)-----------
+#
+# 第一段:内部 location(放在 location / 之前)
+
+ location /seo-templates/ {
+ internal;
+ add_header Content-Type "text/html; charset=utf-8";
+ add_header X-SEOMiddleware "nginx-prerendered";
+ }
+
+# 第二段:在 location / 里必须有(爬虫时重写到上面)
+
+ location / {
+ if ($is_crawler = 1) {
+ rewrite ^ /seo-templates/$seo_file break;
+ }
+ try_files $uri $uri/ /index.html;
+ }
+
+# 说明:root 已在 server 里设为 /www/wwwroot/www.xingfucha.cn,
+# 请求 /seo-templates/index.html 会读文件 .../seo-templates/index.html
+# ---------- 结束 ----------
diff --git a/server/nginx-www.xingfucha.cn.conf b/server/nginx-www.xingfucha.cn.conf
new file mode 100644
index 0000000..ad7febe
--- /dev/null
+++ b/server/nginx-www.xingfucha.cn.conf
@@ -0,0 +1,148 @@
+# 在原有配置基础上增加 SEO 爬虫检测,其余保持不变
+# 部署时请将 public/seo-templates 整个目录上传到服务器:/www/wwwroot/www.xingfucha.cn/seo-templates
+
+server
+{
+ listen 80;
+ listen 443 ssl;
+ listen 443 quic;
+ listen [::]:443 ssl;
+ listen [::]:443 quic;
+ http2 on;
+ listen [::]:80;
+ server_name xingfucha.cn www.xingfucha.cn p.xingfucha.cn;
+ index index.html index.htm default.htm default.html;
+ root /www/wwwroot/www.xingfucha.cn;
+
+ # ========== SEO 爬虫检测与模板映射(请勿删除) ==========
+ set $is_crawler 0;
+ if ($http_user_agent ~* "baiduspider|baiduspider-mobile|baiduspider-image|baiduspider-video|baiduspider-news|baiduboxapp") {
+ set $is_crawler 1;
+ }
+ if ($http_user_agent ~* "googlebot|googlebot-image|googlebot-news|googlebot-mobile|googlebot-video|google-web-snippet") {
+ set $is_crawler 1;
+ }
+ if ($http_user_agent ~* "bingbot|msnbot") {
+ set $is_crawler 1;
+ }
+ if ($http_user_agent ~* "360spider|soha-agent|haosouspider") {
+ set $is_crawler 1;
+ }
+ if ($http_user_agent ~* "sogou spider|sogou news spider|sogou orion spider|sogou-blog") {
+ set $is_crawler 1;
+ }
+ if ($http_user_agent ~* "slurp|sosospider|sosoimagespider|youdaobot|yodaobot") {
+ set $is_crawler 1;
+ }
+ if ($http_user_agent ~* "bytedance-spider|toutiaospider") {
+ set $is_crawler 1;
+ }
+ if ($http_user_agent ~* "facebookexternalhit|facebookcatalog|twitterbot|linkedinbot|whatsapp|telegrambot|viber|line") {
+ set $is_crawler 1;
+ }
+
+ set $seo_file index.html;
+ if ($uri = '/') { set $seo_file index.html; }
+ if ($uri = '/agent') { set $seo_file agent.html; }
+ if ($uri = '/help') { set $seo_file help.html; }
+ if ($uri = '/help/guide') { set $seo_file help-guide.html; }
+ if ($uri = '/example') { set $seo_file example.html; }
+ if ($uri = '/service') { set $seo_file service.html; }
+ if ($uri = '/inquire/personalData') { set $seo_file inquire-personalData.html; }
+ if ($uri = '/inquire/companyinfo') { set $seo_file inquire-companyinfo.html; }
+ if ($uri = '/inquire/preloanbackgroundcheck') { set $seo_file inquire-preloanbackgroundcheck.html; }
+ if ($uri = '/inquire/marriage') { set $seo_file inquire-marriage.html; }
+ if ($uri = '/inquire/backgroundcheck') { set $seo_file inquire-backgroundcheck.html; }
+ if ($uri = '/inquire/homeservice') { set $seo_file inquire-homeservice.html; }
+ # ========== SEO 配置结束 ==========
+
+ #CERT-APPLY-CHECK--START
+ include /www/server/panel/vhost/nginx/well-known/www.xingfucha.cn.conf;
+ #CERT-APPLY-CHECK--END
+
+ #SSL-START
+ #error_page 404/404.html;
+ ssl_certificate /www/server/panel/vhost/cert/www.xingfucha.cn/fullchain.pem;
+ ssl_certificate_key /www/server/panel/vhost/cert/www.xingfucha.cn/privkey.pem;
+ ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
+ ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
+ ssl_prefer_server_ciphers on;
+ ssl_session_tickets on;
+ ssl_session_cache shared:SSL:10m;
+ ssl_session_timeout 10m;
+ add_header Strict-Transport-Security "max-age=31536000";
+ add_header Alt-Svc 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"';
+ error_page 497 https://$host$request_uri;
+ #SSL-END
+
+ #ERROR-PAGE-START
+ #error_page 404 /404.html;
+ #error_page 502 /502.html;
+ #ERROR-PAGE-END
+
+ #REWRITE-START
+ include /www/server/panel/vhost/rewrite/html_www.xingfucha.cn.conf;
+ #REWRITE-END
+
+ location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
+ {
+ return 404;
+ }
+
+ location ~ \.well-known{
+ allow all;
+ }
+
+ if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
+ return 403;
+ }
+
+ location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
+ {
+ expires 30d;
+ error_log /dev/null;
+ access_log /dev/null;
+ }
+
+ location ~ .*\.(js|css)?$
+ {
+ expires 12h;
+ error_log /dev/null;
+ access_log /dev/null;
+ }
+
+ # SEO:爬虫访问时走 /seo-templates/ 内部路径,用 root 找文件(避免 alias 兼容问题)
+ location /seo-templates/ {
+ internal;
+ add_header Content-Type "text/html; charset=utf-8";
+ add_header X-SEOMiddleware "nginx-prerendered";
+ }
+
+ location / {
+ # 爬虫则返回对应 SEO 模板(root 已是 /www/wwwroot/www.xingfucha.cn,故文件为 .../seo-templates/index.html)
+ if ($is_crawler = 1) {
+ rewrite ^ /seo-templates/$seo_file break;
+ }
+ try_files $uri $uri/ /index.html;
+ }
+
+ location /api/v1 {
+ proxy_pass http://127.0.0.1:23204;
+ proxy_set_header Host 127.0.0.1:$server_port;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header REMOTE-HOST $remote_addr;
+ add_header X-Cache $upstream_cache_status;
+ proxy_set_header X-Host $host:$server_port;
+ proxy_set_header X-Scheme $scheme;
+ proxy_connect_timeout 30s;
+ proxy_read_timeout 86400s;
+ proxy_send_timeout 30s;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ }
+
+ access_log /www/wwwlogs/www.xingfucha.cn.log;
+ error_log /www/wwwlogs/www.xingfucha.cn.error.log;
+}
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 0000000..28e51dd
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "xfc-seo-server",
+ "version": "1.0.0",
+ "description": "幸福查SEO优化服务器 - 爬虫检测与静态HTML回退",
+ "main": "server-example-express.js",
+ "scripts": {
+ "start": "node server-example-express.js",
+ "dev": "node server-example-express.js",
+ "generate": "node generate-seo-templates.cjs",
+ "test": "node test-seo.js",
+ "test:crawler": "node test-crawler-detection.js"
+ },
+ "keywords": [
+ "seo",
+ "crawler",
+ "spa",
+ "prerender"
+ ],
+ "author": "xingfucha",
+ "license": "MIT",
+ "dependencies": {
+ "express": "^4.18.2",
+ "compression": "^1.7.4"
+ },
+ "devDependencies": {
+ "nodemon": "^3.0.1"
+ }
+}
diff --git a/server/server-example-express.js b/server/server-example-express.js
new file mode 100644
index 0000000..811d63e
--- /dev/null
+++ b/server/server-example-express.js
@@ -0,0 +1,36 @@
+/**
+ * Express服务器示例
+ * 展示如何集成SEO中间件
+ */
+
+const express = require('express')
+const path = require('path')
+const SEOMiddleware = require('./middleware')
+
+const app = express()
+const port = process.env.PORT || 3000
+
+// 初始化SEO中间件
+const seoMiddleware = new SEOMiddleware({
+ templateDir: path.join(__dirname, '../public/seo-templates'),
+ debug: process.env.NODE_ENV === 'development'
+})
+
+// 应用SEO中间件(必须在静态文件服务之前)
+app.use(seoMiddleware.express())
+
+// 静态文件服务
+app.use(express.static(path.join(__dirname, '../dist')))
+
+// SPA路由处理
+app.get('*', (req, res) => {
+ res.sendFile(path.join(__dirname, '../dist/index.html'))
+})
+
+// 启动服务器
+app.listen(port, () => {
+ console.log(`🚀 服务器运行在 http://localhost:${port}`)
+ console.log(`🔍 SEO中间件已启用`)
+})
+
+module.exports = app
diff --git a/server/test-crawler-detection.js b/server/test-crawler-detection.js
new file mode 100644
index 0000000..d494d78
--- /dev/null
+++ b/server/test-crawler-detection.js
@@ -0,0 +1,112 @@
+/**
+ * 爬虫检测测试脚本
+ * 用于验证爬虫检测功能是否正常工作
+ */
+
+const CrawlerDetector = require('./crawler-detector')
+
+const detector = new CrawlerDetector()
+
+// 测试用例
+const testCases = [
+ // 爬虫User-Agent
+ { userAgent: 'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)', expected: true, description: '百度爬虫' },
+ { userAgent: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', expected: true, description: 'Google爬虫' },
+ { userAgent: 'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)', expected: true, description: '必应爬虫' },
+ { userAgent: 'Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)', expected: true, description: '搜狗爬虫' },
+ { userAgent: '360Spider', expected: true, description: '360爬虫' },
+ { userAgent: 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)', expected: true, description: 'Facebook爬虫' },
+ { userAgent: 'Twitterbot/1.0', expected: true, description: 'Twitter爬虫' },
+ { userAgent: 'LinkedInBot/1.0 (compatible; Mozilla/5.0; +https://www.linkedin.com/help/linkedin/answer/8665)', expected: true, description: 'LinkedIn爬虫' },
+
+ // 正常浏览器User-Agent
+ { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', expected: false, description: 'Chrome浏览器' },
+ { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0', expected: false, description: 'Firefox浏览器' },
+ { userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15', expected: false, description: 'Safari浏览器' },
+ { userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1', expected: false, description: 'iPhone Safari' },
+ { userAgent: 'Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36', expected: false, description: 'Android Chrome' },
+ { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0', expected: false, description: 'Edge浏览器' },
+
+ // 边界情况
+ { userAgent: '', expected: false, description: '空User-Agent' },
+ { userAgent: 'Mozilla/5.0 (compatible; MyBot/1.0)', expected: true, description: '包含bot关键词' },
+ { userAgent: 'Mozilla/5.0 (compatible; Spider/1.0)', expected: true, description: '包含spider关键词' },
+ { userAgent: 'Mozilla/5.0 (compatible; Crawler/1.0)', expected: true, description: '包含crawler关键词' }
+]
+
+console.log('='.repeat(70))
+console.log('爬虫检测测试')
+console.log('='.repeat(70))
+console.log()
+
+let passed = 0
+let failed = 0
+
+testCases.forEach((testCase, index) => {
+ const req = {
+ headers: {
+ 'user-agent': testCase.userAgent
+ }
+ }
+
+ const result = detector.isCrawler(req)
+ const success = result === testCase.expected
+ const status = success ? '✓ 通过' : '✗ 失败'
+ const crawlerType = result ? detector.getCrawlerType(testCase.userAgent) : 'N/A'
+
+ if (success) {
+ passed++
+ console.log(`${status} 测试 ${index + 1}: ${testCase.description}`)
+ } else {
+ failed++
+ console.error(`${status} 测试 ${index + 1}: ${testCase.description}`)
+ console.error(` User-Agent: ${testCase.userAgent.substring(0, 80)}...`)
+ console.error(` 预期: ${testCase.expected}, 实际: ${result}`)
+ }
+
+ if (result) {
+ console.log(` 识别为: ${crawlerType} 爬虫`)
+ }
+})
+
+console.log()
+console.log('='.repeat(70))
+console.log(`测试结果: ${passed} 通过, ${failed} 失败, 共 ${testCases.length} 个测试`)
+console.log('='.repeat(70))
+console.log()
+
+// 测试爬虫类型识别
+console.log('爬虫类型识别测试:')
+console.log('-'.repeat(70))
+
+const crawlerTypes = [
+ { userAgent: 'Baiduspider', expected: 'baidu', description: '百度爬虫' },
+ { userAgent: 'Googlebot', expected: 'google', description: 'Google爬虫' },
+ { userAgent: 'bingbot', expected: 'bing', description: '必应爬虫' },
+ { userAgent: '360spider', expected: '360', description: '360爬虫' },
+ { userAgent: 'sogou spider', expected: 'sogou', description: '搜狗爬虫' },
+ { userAgent: 'facebookexternalhit', expected: 'facebook', description: 'Facebook爬虫' },
+ { userAgent: 'Twitterbot', expected: 'twitter', description: 'Twitter爬虫' },
+ { userAgent: 'linkedinbot', expected: 'linkedin', description: 'LinkedIn爬虫' }
+]
+
+let typePassed = 0
+crawlerTypes.forEach(test => {
+ const result = detector.getCrawlerType(test.userAgent)
+ const success = result === test.expected
+
+ if (success) {
+ typePassed++
+ console.log(`✓ ${test.description}: ${result}`)
+ } else {
+ console.error(`✗ ${test.description}: 预期 ${test.expected}, 实际 ${result}`)
+ }
+})
+
+console.log()
+console.log('='.repeat(70))
+console.log(`爬虫类型识别: ${typePassed}/${crawlerTypes.length} 正确`)
+console.log('='.repeat(70))
+
+// 退出码
+process.exit(failed === 0 ? 0 : 1)
diff --git a/server/test-seo.js b/server/test-seo.js
new file mode 100644
index 0000000..84b0491
--- /dev/null
+++ b/server/test-seo.js
@@ -0,0 +1,176 @@
+/**
+ * SEO 端到端检测脚本
+ * 模拟爬虫与普通用户请求,验证是否返回正确的页面
+ *
+ * 使用前请先启动服务器: npm run start
+ * 然后运行: npm run test 或 node test-seo.js
+ */
+
+const http = require('http')
+const https = require('https')
+
+const BASE_URL = process.env.SEO_TEST_URL || 'http://localhost:3000'
+
+// 要检测的路由及期望的 SEO 标题关键词
+const ROUTES = [
+ { path: '/', titleKeyword: '幸福查官网' },
+ { path: '/agent', titleKeyword: '幸福查代理' },
+ { path: '/help', titleKeyword: '幸福查帮助中心' },
+ { path: '/inquire/personalData', titleKeyword: '个人生活信用' }
+]
+
+function request(url, userAgent) {
+ return new Promise((resolve, reject) => {
+ const lib = url.startsWith('https') ? https : http
+ const req = lib.get(url, {
+ headers: { 'User-Agent': userAgent },
+ timeout: 10000
+ }, res => {
+ const chunks = []
+ res.on('data', chunk => chunks.push(chunk))
+ res.on('end', () => {
+ resolve({
+ statusCode: res.statusCode,
+ headers: res.headers,
+ body: Buffer.concat(chunks).toString('utf-8')
+ })
+ })
+ })
+ req.on('error', reject)
+ req.on('timeout', () => {
+ req.destroy()
+ reject(new Error('请求超时'))
+ })
+ })
+}
+
+function extractTitle(html) {
+ const match = html.match(/