This commit is contained in:
Mrx
2026-02-28 15:24:44 +08:00
parent 7fc01544de
commit e021548adf
5 changed files with 0 additions and 1091 deletions

View File

@@ -1,355 +0,0 @@
# SPA SEO 优化解决方案
## 📋 方案概述
针对 SPA 应用 SEO 问题,采用**爬虫检测 + 静态 HTML 回退**方案:
1. **爬虫检测**识别搜索引擎爬虫百度、Google、必应、搜狗等
2. **静态 HTML**:为爬虫提供预渲染的 HTML 模板,包含完整 TDK、OG、canonical、结构化数据
3. **正常用户**:继续使用 SPA体验不受影响
**配置统一**:服务端 SEO 模板内容与前端 `src/composables/useSEO.js` 保持一致(标题、描述、关键词、域名),域名默认为 `https://www.quannengcha.com`(全能查)。可通过环境变量 `SEO_BASE_URL` 覆盖。
## 🏗️ 项目结构
```
server/
├── crawler-detector.js # 爬虫检测模块
├── middleware.js # SEO 中间件Express/Koa路由与 useSEO.js 一致
├── generate-seo-templates.cjs # SEO 模板生成器(与 useSEO.js 同步)
├── server-example-express.js # Express 服务器示例
├── nginx-www.quannengcha.com.conf # 全能查 Nginx 配置quannengcha.com
├── nginx-www.tianyuancha.cn.conf # 天远查 Nginx 配置tianyuancha.cn
├── nginx-www.tianyuandb.com.conf # 天远数据 Nginx 配置tianyuandb.com
├── test-seo.js # SEO 端到端检测脚本
└── README-SEO.md # 本文档
public/
└── seo-templates/ # SEO 静态模板目录(运行 generate 后生成)
├── index.html
├── agent-system-guide.html
├── inquire-riskassessment.html
├── inquire-companyinfo.html
├── inquire-preloanbackgroundcheck.html
├── inquire-marriage.html
├── inquire-backgroundcheck.html
├── inquire-homeservice.html
├── inquire-consumerFinanceReport.html
├── agent.html
├── help.html
├── help-guide.html
├── example.html
├── service.html
├── promote.html
└── ...
```
## 🚀 快速开始
### 步骤1生成 SEO 模板
```bash
cd server
node generate-seo-templates.cjs
# 或 npm run generate
```
这会在 `public/seo-templates/` 下生成所有页面的静态 HTML 模板,内容与 `src/composables/useSEO.js` 一致。
### 步骤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
- 全能查站点:参考 `server/nginx-www.quannengcha.com.conf`,将 `root``server_name`、证书路径改为你的服务器路径。
- 天远查站点:参考 `server/nginx-www.tianyuancha.cn.conf`
- 部署时把 `public/seo-templates/` 整目录上传到服务器 `root` 下的 `static-pages/`
```bash
# 复制并修改配置
cp server/nginx-www.quannengcha.com.conf /etc/nginx/sites-available/quannengcha
nano /etc/nginx/sites-available/quannengcha # 修改 root、证书等
# 启用并重载
ln -s /etc/nginx/sites-available/quannengcha /etc/nginx/sites-enabled/
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'
}
```
### 模板生成配置
**推荐**:页面 SEO 以 `src/composables/useSEO.js` 为唯一来源;修改标题/描述/关键词时只改 `useSEO.js` 中的 `routeConfigs`,然后同步到服务端:
-`server/generate-seo-templates.cjs``pageSEOConfigs` 中保持与 `useSEO.js` 一致(含新增路由与 `BASE_URL`)。
-`server/middleware.js``routeTemplateMap` 中为新路由添加映射。
- 若用 Nginx在对应 conf 的 `$seo_file` 中增加 `if ($uri = '/新路径') { set $seo_file 新模板.html; }`
新增页面示例(`generate-seo-templates.cjs`
```javascript
'new-template.html': {
title: '页面标题',
description: '页面描述',
keywords: '关键词1,关键词2',
url: 'https://www.tianyuandb.com/new-route'
}
```
## 📝 自定义模板
### 修改模板样式
编辑 `generate-seo-templates.js` 中的 `generateHTMLTemplate` 函数:
```javascript
function generateHTMLTemplate(config) {
return `<!DOCTYPE html>
<html>
<head>
<!-- 头部信息 -->
<style>
/* 自定义样式 */
body { ... }
</style>
</head>
<body>
<!-- 自定义内容 -->
</body>
</html>`
}
```
### 添加结构化数据
模板已包含基本的结构化数据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
# 本地/线上 SEO 检测(会请求爬虫 UA 与普通 UA
cd server
SEO_TEST_URL=http://localhost:3000 node test-seo.js
# 或线上SEO_TEST_URL=https://www.tianyuandb.com node test-seo.js
```
```bash
# 查看爬虫看到的标题
curl -s -A "Baiduspider/2.0" https://www.tianyuandb.com/ | grep -o '<title>.*</title>'
# 检查 meta 与 canonical
curl -s -A "Googlebot" https://www.tianyuandb.com/ | grep -E '<meta name="description"|<meta name="keywords"|<link rel="canonical"'
# 检查结构化数据
curl -s -A "Baiduspider" https://www.tianyuandb.com/ | grep -A 20 'application/ld+json'
```
## 📊 维护建议
### 定期更新爬虫列表
搜索引擎爬虫的User-Agent可能会更新建议定期检查并更新
- 百度https://ziyuan.baidu.com/spider/
- Googlehttps://support.google.com/webmasters/answer/1061943
### 保持模板内容同步
`useSEO.js` 中页面 SEO 更新时,重新生成模板并部署:
```bash
cd server
node generate-seo-templates.cjs
# 将 public/seo-templates/ 上传到服务器对应目录
```
可选定时任务(例如每小时同步一次):
```bash
0 * * * * cd /path/to/tydata-webview-v2/server && node generate-seo-templates.cjs
```
### 监控爬虫访问
在服务器日志中监控爬虫访问情况:
```bash
# 查看百度爬虫访问
grep "Baiduspider" /var/log/nginx/access.log
# 查看Google爬虫访问
grep "Googlebot" /var/log/nginx/access.log
```
## 🐛 常见问题
### Q1: 爬虫访问的是SPA还是静态HTML
检查响应头:
```bash
curl -I -A "Baiduspider" http://www.xingfucha.cn/
```
若看到 `X-SEOMiddleware: prerendered`Node 中间件)或 `X-SEOMiddleware: nginx-prerendered`Nginx说明返回的是 SEO 静态 HTML。
### Q2: 如何调试爬虫检测?
启用调试模式:
```javascript
const seoMiddleware = new SEOMiddleware({
templateDir: 'public/seo-templates',
debug: true // 查看详细日志
})
```
### Q3: 模板内容如何更新?
`src/composables/useSEO.js` 为准修改标题/描述/关键词,再在 `server/generate-seo-templates.cjs` 中同步 `pageSEOConfigs`,然后执行:
```bash
node generate-seo-templates.cjs
```
### Q4: 如何处理动态内容?
静态模板只包含静态内容。如果需要包含动态数据,可以考虑:
1. **预渲染服务**:如 Prerender.io
2. **服务端渲染**:迁移到 Nuxt.js
3. **混合方案**:静态模板 + AJAX加载动态内容
### Q5: 爬虫列表是否会误判?
如果某个用户被误判为爬虫,可以:
1. 检查User-Agent是否包含爬虫关键词
2. 在检测器中添加白名单
3. 使用IP地址作为辅助判断
## 📚 参考资源
- [百度搜索蜘蛛协议](https://ziyuan.baidu.com/spider/)
- [Google 爬虫文档](https://developers.google.com/search/docs/crawling-indexing/overview-google-crawlers)
- [结构化数据规范](https://schema.org/)
- [Open Graph 协议](https://ogp.me/)
## 🆘 支持
如有问题,请检查:
1. 模板目录是否存在:`public/seo-templates/`
2. 模板文件是否生成:运行 `node generate-seo-templates.js`
3. 服务器配置是否正确检查中间件或Nginx配置
4. 爬虫User-Agent是否匹配查看检测器日志
## 📄 许可
本方案可自由使用和修改。

View File

@@ -1,419 +0,0 @@
# Nginx 配置 - www.quannengcha.com全能查
# 含爬虫检测 + SEO 静态页回退,与 useSEO.js / generate-seo-templates.cjs 路由一致
# 部署时将 public/seo-templates/ 下所有 .html 拷贝到 /www/sites/www.quannengcha.com/static-pages/
server {
listen 80;
listen 443 ssl http2;
server_name www.quannengcha.com quannengcha.com p.quannengcha.com;
# 网站根目录SPA
root /www/sites/www.quannengcha.com/index;
# SEO 静态页面目录(与 generate-seo-templates.cjs 输出一致)
set $static_root /www/sites/www.quannengcha.com/index/static-pages;
# 默认首页
index index.php index.html index.htm default.php default.htm default.html;
# ========================================
# 爬虫检测(核心 SEO 逻辑)
# ========================================
set $is_bot 0;
# Google 爬虫
if ($http_user_agent ~* (googlebot|googlebot-image|googlebot-news|googlebot-video|mediapartners-google|adsbot-google)) {
set $is_bot 1;
}
# 百度爬虫
if ($http_user_agent ~* (baiduspider|baiduspider-mobile|baiduspider-image|baiduspider-video|baiduspider-news)) {
set $is_bot 1;
}
# 必应爬虫
if ($http_user_agent ~* (bingbot|msnbot|bingpreview)) {
set $is_bot 1;
}
# 360 爬虫
if ($http_user_agent ~* "360spider|360Spider") {
set $is_bot 1;
}
# 搜狗爬虫
if ($http_user_agent ~* "(sogou spider|sogou-orion|Sogou web spider)") {
set $is_bot 1;
}
# 头条爬虫
if ($http_user_agent ~* "bytespider|Bytespider") {
set $is_bot 1;
}
# 神马爬虫
if ($http_user_agent ~* "yisouspider|YisouSpider") {
set $is_bot 1;
}
# 其他常见爬虫
if ($http_user_agent ~* "(spider|crawl|bot|slurp|yandex|duckduckbot|facebookexternalhit|twitterbot|linkedinbot|pinterest|applebot)") {
set $is_bot 1;
}
# ========================================
# 通用代理头设置
# ========================================
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
# ========================================
# 日志配置
# ========================================
access_log /www/sites/www.quannengcha.com/log/access.log main;
error_log /www/sites/www.quannengcha.com/log/error.log;
# ========================================
# Let's Encrypt 验证
# ========================================
location ^~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
}
# ========================================
# SSL 证书配置
# ========================================
ssl_certificate /www/sites/www.quannengcha.com/ssl/fullchain.pem;
ssl_certificate_key /www/sites/www.quannengcha.com/ssl/privkey.pem;
ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
proxy_set_header X-Forwarded-Proto https;
add_header Strict-Transport-Security "max-age=31536000";
# ========================================
# SEO 静态文件sitemap.xml, robots.txt
# ========================================
location = /sitemap.xml {
root /www/sites/www.quannengcha.com/static-pages;
default_type application/xml;
}
location = /robots.txt {
root /www/sites/www.quannengcha.com/static-pages;
default_type text/plain;
}
# ========================================
# 首页(爬虫 → 静态页,用户 → SPA
# ========================================
location = / {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /index.html break;
}
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
add_header Pragma "no-cache";
add_header Expires 0;
}
# ========================================
# SEO 关键页面(与 useSEO.js / middleware 一致;子路径在前)
# ========================================
# 合作政策指南(子路径须在 /agent 之前)
location = /agent/system-guide {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /agent-system-guide.html break;
}
try_files $uri $uri/ /index.html;
}
# 个人综合风险分析
location = /inquire/riskassessment {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /inquire-riskassessment.html break;
}
try_files $uri $uri/ /index.html;
}
# 企业工商信用画像
location = /inquire/companyinfo {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /inquire-companyinfo.html break;
}
try_files $uri $uri/ /index.html;
}
# 综合履约评分检测
location = /inquire/preloanbackgroundcheck {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /inquire-preloanbackgroundcheck.html break;
}
try_files $uri $uri/ /index.html;
}
# 婚前综合背景了解
location = /inquire/marriage {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /inquire-marriage.html break;
}
try_files $uri $uri/ /index.html;
}
# 职场背景核验报告
location = /inquire/backgroundcheck {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /inquire-backgroundcheck.html break;
}
try_files $uri $uri/ /index.html;
}
# 家政人员背景核实
location = /inquire/homeservice {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /inquire-homeservice.html break;
}
try_files $uri $uri/ /index.html;
}
# 个人履约能力评估
location = /inquire/consumerFinanceReport {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /inquire-consumerFinanceReport.html break;
}
try_files $uri $uri/ /index.html;
}
# 代理中心
location = /agent {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /agent.html break;
}
try_files $uri $uri/ /index.html;
}
# 使用指南(子路径须在 /help 之前)
location = /help/guide {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /help-guide.html break;
}
try_files $uri $uri/ /index.html;
}
# 帮助中心
location = /help {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /help.html break;
}
try_files $uri $uri/ /index.html;
}
# 示例报告
location = /example {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /example.html break;
}
try_files $uri $uri/ /index.html;
}
# 客服中心
location = /service {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /service.html break;
}
try_files $uri $uri/ /index.html;
}
# 合伙人计划
location = /promote {
if ($is_bot = 1) {
root /www/sites/www.quannengcha.com/static-pages;
rewrite ^ /promote.html break;
}
try_files $uri $uri/ /index.html;
}
# ========================================
# API 代理配置
# ========================================
# 处理后端API请求
location /api {
proxy_pass http://127.0.0.1:17990;
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";
}
location /s/ {
proxy_pass http://127.0.0.1:21204;
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";
}
location /api/v1 {
set $target_backend "http://127.0.0.1:21204";
if ($host ~* ^([a-zA-Z0-9-]+\.)?tianyuancha\.cn$) {
set $target_backend "http://127.0.0.1:20004";
}
if ($host ~* ^([a-zA-Z0-9-]+\.)?quannengcha\.com$) {
set $target_backend "http://127.0.0.1:21204";
}
proxy_pass $target_backend;
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";
}
# V2
location /apiv2 {
proxy_pass http://127.0.0.1:18990;
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;
}
location ^~ /api/v1/chat {
resolver 8.8.8.8 114.114.114.114 valid=10s;
resolver_timeout 5s;
set $backend "chat.guimiaokeji.com";
rewrite ^/api/v1/(.*)$ /$1 break;
proxy_pass https://$backend;
proxy_set_header Host $backend;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
add_header X-Cache $upstream_cache_status;
add_header Cache-Control no-cache;
proxy_ssl_server_name off;
proxy_buffering off;
}
# ========================================
# 静态资源缓存(图片、字体等)
# ========================================
location ~* \.(png|jpg|jpeg|gif|ico|svg|webp|woff|woff2|ttf|eot|otf)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
# ========================================
# HTML/JS/CSS 无缓存策略
# ========================================
location ~* \.(html|htm|js|css|json|xml)$ {
add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0";
add_header Pragma "no-cache";
add_header Expires "0";
}
# ========================================
# SPA 路由回退(其他所有路由)
# ========================================
location / {
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
add_header Pragma "no-cache";
add_header Expires 0;
}
# ========================================
# 错误页面
# ========================================
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# ========================================
# Gzip 压缩
# ========================================
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json image/svg+xml;
# ========================================
# 安全头
# ========================================
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# ========================================
# HTTP 强制跳转 HTTPS
# ========================================
if ($scheme = http) {
return 301 https://$host$request_uri;
}
# ========================================
# 引入重定向配置
# ========================================
include /www/sites/www.quannengcha.com/redirect/*.conf;
}

View File

@@ -1,211 +0,0 @@
# SEO 检测指南
## 一、本地快速检测
### 1. 只测爬虫识别逻辑(不启动服务)
```bash
cd server
node test-crawler-detection.js
```
会跑多组 User-Agent看是否把百度/Google 等识别为爬虫、普通浏览器识别为非爬虫。
### 2. 端到端检测(需先启动服务)
**步骤 1启动 SEO 服务器**
```bash
cd server
npm install
npm run start
```
**步骤 2另开一个终端运行检测**
```bash
cd server
npm run test
```
或指定地址:
```bash
# Windows PowerShell
$env:SEO_TEST_URL="http://localhost:3000"; node test-seo.js
# 若部署在线上,可测线上
$env:SEO_TEST_URL="https://www.xingfucha.cn"; node test-seo.js
```
脚本会:
-**百度爬虫 UA** 请求首页、代理页、帮助中心、个人查询等
- 检查响应里是否有:`<title>``<meta name="description">``<meta name="keywords">``<link rel="canonical">`
-**普通浏览器 UA** 再请求一遍,确认仍是 200SPA 正常)
全部通过即说明:爬虫拿到的是 SEO 模板,普通用户拿到的是 SPA。
---
## 二、用 curl 手动检测
在服务器已启动的前提下,在终端执行:
### 爬虫应拿到“带 TDK 的 HTML”
```bash
# 模拟百度爬虫请求首页
curl -s -A "Baiduspider/2.0" http://localhost:3000/ | findstr /i "title description keywords canonical"
```
应能看到包含「天远数据」的 title以及 description、keywords、canonical 等标签。
**Windows 下中文乱码说明**:服务器返回的是 UTF-8CMD 默认是 GBK直接 `curl … | findstr` 会看到乱码(如 `澶╄繙鏁版嵁`)或出现 “FINDSTR: 写入错误”。可任选一种方式解决:
```cmd
:: 方式 1先切到 UTF-8 再执行CMD
chcp 65001
curl -s -A "Baiduspider/2.0" https://www.tianyuandb.com/ | findstr /i "title description"
```
```powershell
# 方式 2PowerShell 下指定输出编码
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
curl -s -A "Baiduspider/2.0" https://www.tianyuandb.com/ | Select-String -Pattern "title|description"
```
```cmd
:: 方式 3保存到文件后用编辑器打开任意编码都行
curl -s -A "Baiduspider/2.0" https://www.tianyuandb.com/ -o seo-test.html
:: 用记事本/VSCode 打开 seo-test.html选 UTF-8 即可看到正确中文
```
```bash
# 看完整 HTML 前几行(含 <head>
curl -s -A "Baiduspider/2.0" http://localhost:3000/ | more
```
### 普通用户应拿到 SPA一般是带 script 的 index.html
```bash
# 不带爬虫 UA相当于普通浏览器
curl -s http://localhost:3000/ | findstr /i "script root app"
```
通常会有 `id="app"` 或大量 `<script>`,说明是前端 SPA。
### 看响应头(若用了 Node 中间件)
```bash
curl -I -A "Baiduspider/2.0" http://localhost:3000/
```
若返回里有 `X-SEOMiddleware: prerendered`,说明走的是 SEO 中间件、返回的是预渲染 HTML。
---
## 三、用浏览器“伪装”爬虫(可选)
1. 打开 Chrome DevTools (F12) → Network。
2. 右键列表头 → 勾选 “User-Agent”或先在 More tools 里加自定义请求头)。
3. 使用扩展(如 “User-Agent Switcher”把 UA 改成:
- `Baiduspider/2.0`
4. 刷新页面,在 Elements 里看 `<head>`
- 应看到正确的 `<title>``<meta name="description">``<meta name="keywords">` 等。
注意:若前端是 SPA同一 URL 在浏览器里仍可能先加载 SPA 再改 title用 curl 用爬虫 UA 请求,更能代表爬虫真实看到的内容。
---
## 四、线上/生产环境检测
### 1. 用本机脚本测线上
```bash
cd server
$env:SEO_TEST_URL="https://www.xingfucha.cn"; node test-seo.js
```
Linux/Mac 用 `export SEO_TEST_URL=https://www.xingfucha.cn` 再运行 `node test-seo.js`。)
### 2. 用 curl 测线上
```bash
curl -s -A "Baiduspider/2.0" https://www.xingfucha.cn/ | findstr /i "title description"
curl -I -A "Baiduspider/2.0" https://www.xingfucha.cn/
```
### 3. 使用搜索引擎工具
- **百度** [百度搜索资源平台](https://ziyuan.baidu.com/) → 抓取诊断 / 抓取频次,看抓取是否成功。
- **Google** [Google Search Console](https://search.google.com/search-console) → URL 检查,输入首页或内页 URL查看“已编入索引”的页面快照。
---
## 五、检测结果对照
| 检测项 | 预期结果 |
|------------------|----------|
| 爬虫 UA 请求 | 返回 200HTML 内含完整 title、description、keywords、canonical |
| 爬虫响应头 | 若用 Node 中间件,有 `X-SEOMiddleware: prerendered` |
| 普通浏览器请求 | 返回 200为 SPA 的 index.html#app 或大量 script |
| test-crawler-detection.js | 全部用例通过 |
| test-seo.js | 全部路由“爬虫拿到 SEO 模板 + 普通用户正常” |
若某一项不符合,按下面排查:
- **爬虫也拿到 SPA**:检查 Nginx/Node 里爬虫判断和 SEO 模板路径、路由映射是否正确。
- **普通用户报错或空白**:检查 SPA 静态资源和 fallback 的 index.html 是否正常。
- **标题/描述不对**:检查 `public/seo-templates/` 下对应模板是否已重新生成(`node generate-seo-templates.cjs`)。
---
## 六、爬虫请求返回 404 时排查
当执行 `curl -s -A "Baiduspider/2.0" https://www.xingfucha.cn/` 得到 **404 Not Found** 时,按下面顺序在**服务器上**检查。
### 1. 确认已接入 SEO 配置
- 若你**还没**在宝塔里替换/合并过 `server/nginx-www.xingfucha.cn.conf` 里的 SEO 相关配置,爬虫仍会走原来的 `location /`,不会返回 SEO 模板。
- **操作**:在宝塔 → 网站 → www.xingfucha.cn → 配置文件,确认存在:
- 上面的 `set $is_crawler``set $seo_file` 以及一堆 `if ($http_user_agent ...)``if ($uri = '/') ...`
- `location ~ ^/__seo__/(.+)$ { ... internal; }`
-`location /` 里有 `if ($is_crawler = 1) { rewrite ^ /__seo__/$seo_file break; }`
- 修改后执行 `nginx -t`,再重载 Nginx。
### 2. 确认 SEO 模板目录和文件存在
404 常见原因是 Nginx 去读 SEO 模板时路径不对或文件不存在。
在**服务器**上执行(路径按你实际部署的来,一般为宝塔默认):
```bash
# Linux 服务器上
ls -la /www/wwwroot/www.xingfucha.cn/seo-templates/
cat /www/wwwroot/www.xingfucha.cn/seo-templates/index.html | head -5
```
-`seo-templates` 不存在或没有 `index.html`,需要把本地的 `public/seo-templates/` 整个目录上传到服务器的 `/www/wwwroot/www.xingfucha.cn/seo-templates/`(与配置里的 `alias` 路径一致)。
- 若目录名或路径和 Nginx 里 `alias` 不一致(例如多写了 `public` 或少了一层目录),改成与配置一致或改配置里的 `alias`
### 3. 看 Nginx 错误日志
在服务器上:
```bash
tail -20 /www/wwwlogs/www.xingfucha.cn.error.log
```
再发一次爬虫请求,看是否有 `open() ".../seo-templates/xxx.html" failed (2: No such file or directory)` 之类,根据路径修正目录或配置。
### 4. 快速对照
| 现象 | 可能原因 | 处理 |
|------|----------|------|
| 爬虫返回 404 | 未接入 SEO 配置 | 按 1 合并/替换 Nginx 配置并重载 |
| 爬虫返回 404 | 模板目录或文件不存在 | 按 2 上传/创建 `seo-templates` 并保证有 `index.html` |
| 爬虫返回 404 | alias 路径错误 | 对照 error.log 修正 `alias` 或目录结构 |
| 爬虫返回 200 但仍是 SPA | 爬虫未命中 SEO 逻辑 | 检查 `$is_crawler``$seo_file``rewrite` 是否生效 |
按上述步骤即可完成从本地到线上的 SEO 检测。

View File

@@ -1,56 +0,0 @@
# 宝塔环境 Nginx SEO 配置说明
## 1. 已生成的配置文件
- **`server/nginx-www.tianyuandb.com.conf`**天远数据站点tianyuandb.com完整 server 配置,含 SEO 爬虫检测与静态模板,与 **`src/composables/useSEO.js`** 路由一致。
- **`server/nginx-www.xingfucha.cn.conf`**:幸福查站点示例,结构相同,含 `historyQuery``/agent/promote``/agent/invitation` 等路由。
按实际域名二选一或复制后改 `server_name``root`、证书路径。
## 2. 部署前准备:上传 SEO 模板
在服务器上要有 SEO 静态 HTML 目录,路径与站点 `root` 一致,例如:
- 天远数据:`/www/wwwroot/www.tianyuandb.com/seo-templates/`
- 幸福查:`/www/wwwroot/www.xingfucha.cn/seo-templates/`
操作步骤:
1. 本地生成模板(与 useSEO.js 同步):
```bash
cd server
npm run generate
```
2. 将本地的 **`tydata-webview-v2/public/seo-templates/`** 整个目录上传到服务器对应站点的 `seo-templates/` 目录。
目录下应有:`index.html`、`historyQuery.html`、`agent.html`、`agent-promote.html`、`agent-invitation.html`、`help.html`、`help-guide.html`、`example.html`、`service.html`、`inquire-*.html` 等。
## 3. 在宝塔里修改 Nginx 配置
1. 登录宝塔 → **网站** → 找到对应站点(如 www.tianyuandb.com→ **设置** → **配置文件**。
2. 应用 SEO
- **方式 A**:打开 **`server/nginx-www.tianyuandb.com.conf`**(或 xingfucha 版),复制从 `# ========== SEO 爬虫检测` 到 `# ========== SEO 配置结束` 的整段,以及 **`location /seo-templates/`** 和 **`location /`** 两块,合并进当前 server保留 SSL、include、api、日志等
- **方式 B**:用示例的整个 server 块替换当前站点 server 块(先备份),并修改 `server_name`、`root`、证书路径。
3. 保存后 **重载 Nginx**`nginx -t && nginx -s reload`。
## 4. 配置要点说明
- **爬虫判断**:按 `User-Agent` 识别百度、Google、必应、360、搜狗、头条、社交媒体等爬虫爬虫访问时走 SEO 逻辑。
- **路由与模板**`$uri` 与 `$seo_file` 对应关系已在配置中写好(如 `/`→index.html`/historyQuery`→historyQuery.html`/agent/promote`→agent-promote.html 等),与 `public/seo-templates` 下文件名一致。
- **内部 location**`/seo-templates/` 为 internal仅由 `location /` 内 rewrite 使用,爬虫看到的仍是正常 URL内容来自 `seo-templates` 下的静态 HTML。
## 5. 验证
将下面域名换成你的站点后执行:
```bash
# 天远数据示例
curl -sI -A "Baiduspider/2.0" https://www.tianyuandb.com/
curl -s -A "Baiduspider/2.0" https://www.tianyuandb.com/ | grep -o '<title>.*</title>'
```
若看到正确标题和响应头 `X-SEOMiddleware: nginx-prerendered`,说明 SEO 已生效。
**若得到 404**:按 **`server/如何检测.md`** 中「爬虫请求返回 404 时排查」检查:是否已接入 SEO 配置、`seo-templates` 目录与文件是否存在、error 日志。
更多检测:**`server/如何检测.md`**、**`npm run test`**(需先启动本地服务)。

View File

@@ -1,50 +0,0 @@
# 天远数据 tianyuandb.com SEO 部署说明
## 1. 生成 tianyuandb 用 SEO 模板
在项目根目录或 `server` 目录执行(使用当前站点域名生成 canonical/og:url
```bash
cd server
SEO_BASE_URL=https://www.tianyuandb.com node generate-seo-templates.cjs
```
会在 `public/seo-templates/` 下生成 15 个 HTML 文件,内容里的链接均为 `https://www.tianyuandb.com`
## 2. 上传模板到服务器
**`tydata-webview-v2/public/seo-templates/`** 整个目录上传到服务器,目标路径:
```text
/www/sites/www.tianyuandb.com/index/seo-templates/
```
即与站点 `root` 同级,保证存在:
`/www/sites/www.tianyuandb.com/index/seo-templates/index.html`
`historyQuery.html``agent.html``agent-promote.html` 等。
## 3. 使用 Nginx 配置
- 配置文件:**`server/nginx-www.tianyuandb.com.conf`**
- 复制该文件内容到线上 Nginx 对应站点的 server 配置(或直接替换该站点的 server 块,注意先备份)。
- 确认以下路径与你的环境一致,按需修改:
- `root /www/sites/www.tianyuandb.com/index`
- `ssl_certificate` / `ssl_certificate_key`
- `include /www/sites/www.tianyuandb.com/redirect/*.conf`
- `proxy_pass http://127.0.0.1:21004`API 端口)
重载 Nginx
```bash
nginx -t && nginx -s reload
```
## 4. 验证
```bash
# 应返回带 title/description 的 HTML且响应头含 X-SEOMiddleware
curl -sI -A "Baiduspider/2.0" https://www.tianyuandb.com/
curl -s -A "Baiduspider/2.0" https://www.tianyuandb.com/ | grep -o '<title>.*</title>'
```
看到正确标题和 `X-SEOMiddleware: nginx-prerendered` 即表示 SEO 已生效。