f
This commit is contained in:
@@ -119,9 +119,9 @@
|
||||
></script>
|
||||
|
||||
<!-- 预加载关键资源 -->
|
||||
<link rel="preconnect" href="https://www.zhinengcha.cn" />
|
||||
<link rel="preconnect" href="https://www.quannengcha.com" />
|
||||
<link rel="preconnect" href="https://res.wx.qq.com" />
|
||||
<link rel="dns-prefetch" href="https://www.zhinengcha.cn" />
|
||||
<link rel="dns-prefetch" href="https://www.quannengcha.com" />
|
||||
<link rel="dns-prefetch" href="https://res.wx.qq.com" />
|
||||
|
||||
<style>
|
||||
|
||||
@@ -44,7 +44,7 @@ Disallow: /js/
|
||||
Disallow: /css/
|
||||
|
||||
# 网站地图
|
||||
Sitemap: https://www.zhinengcha.cn/sitemap.xml
|
||||
Sitemap: https://www.quannengcha.com/sitemap.xml
|
||||
|
||||
# 爬取延迟(毫秒)
|
||||
Crawl-delay: 1
|
||||
|
||||
80
public/seo-templates/agent-system-guide.html
Normal file
80
public/seo-templates/agent-system-guide.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>全能查合作政策指南_合作伙伴权益与结算说明_官方文档</title>
|
||||
|
||||
<meta name="description" content="全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。">
|
||||
<meta name="keywords" content="合作伙伴政策,服务费结算,渠道等级说明,业务操作指南,代理系统后台">
|
||||
|
||||
<meta property="og:title" content="全能查合作政策指南_合作伙伴权益与结算说明_官方文档">
|
||||
<meta property="og:description" content="全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/agent/system-guide">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="全能查合作政策指南_合作伙伴权益与结算说明_官方文档">
|
||||
<meta name="twitter:description" content="全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/agent/system-guide">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/agent/system-guide">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "全能查合作政策指南_合作伙伴权益与结算说明_官方文档",
|
||||
"description": "全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。",
|
||||
"url": "https://www.quannengcha.com/agent/system-guide",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>全能查合作政策指南_合作伙伴权益与结算说明_官方文档</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/agent/system-guide">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/agent.html
Normal file
80
public/seo-templates/agent.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>全能查代理 - 免费开通代理权限 | 大数据风险报告代理</title>
|
||||
|
||||
<meta name="description" content="全能查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。">
|
||||
<meta name="keywords" content="全能查代理, 免费代理, 大数据风险报告代理, 代理权限, 代理收益">
|
||||
|
||||
<meta property="og:title" content="全能查代理 - 免费开通代理权限 | 大数据风险报告代理">
|
||||
<meta property="og:description" content="全能查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/agent">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="全能查代理 - 免费开通代理权限 | 大数据风险报告代理">
|
||||
<meta name="twitter:description" content="全能查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/agent">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/agent">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "全能查代理 - 免费开通代理权限 | 大数据风险报告代理",
|
||||
"description": "全能查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。",
|
||||
"url": "https://www.quannengcha.com/agent",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>全能查代理 - 免费开通代理权限 | 大数据风险报告代理</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/agent">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/example.html
Normal file
80
public/seo-templates/example.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>示例报告 - 全能查报告展示 | 大数据风险报告样例</title>
|
||||
|
||||
<meta name="description" content="全能查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。">
|
||||
<meta name="keywords" content="示例报告, 报告展示, 报告样例, 大数据风险报告, 婚姻查询报告">
|
||||
|
||||
<meta property="og:title" content="示例报告 - 全能查报告展示 | 大数据风险报告样例">
|
||||
<meta property="og:description" content="全能查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/example">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="示例报告 - 全能查报告展示 | 大数据风险报告样例">
|
||||
<meta name="twitter:description" content="全能查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/example">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/example">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "示例报告 - 全能查报告展示 | 大数据风险报告样例",
|
||||
"description": "全能查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。",
|
||||
"url": "https://www.quannengcha.com/example",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>示例报告 - 全能查报告展示 | 大数据风险报告样例</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/example">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/help-guide.html
Normal file
80
public/seo-templates/help-guide.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>使用指南 - 全能查操作教程 | 功能说明</title>
|
||||
|
||||
<meta name="description" content="全能查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。">
|
||||
<meta name="keywords" content="使用指南, 操作教程, 功能说明, 快速上手, 全能查教程">
|
||||
|
||||
<meta property="og:title" content="使用指南 - 全能查操作教程 | 功能说明">
|
||||
<meta property="og:description" content="全能查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/help/guide">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="使用指南 - 全能查操作教程 | 功能说明">
|
||||
<meta name="twitter:description" content="全能查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/help/guide">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/help/guide">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "使用指南 - 全能查操作教程 | 功能说明",
|
||||
"description": "全能查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。",
|
||||
"url": "https://www.quannengcha.com/help/guide",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>使用指南 - 全能查操作教程 | 功能说明</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/help/guide">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/help.html
Normal file
80
public/seo-templates/help.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>帮助中心 - 全能查使用指南 | 常见问题解答</title>
|
||||
|
||||
<meta name="description" content="全能查帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。">
|
||||
<meta name="keywords" content="全能查帮助, 使用指南, 常见问题, 操作教程, 客服支持">
|
||||
|
||||
<meta property="og:title" content="帮助中心 - 全能查使用指南 | 常见问题解答">
|
||||
<meta property="og:description" content="全能查帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/help">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="帮助中心 - 全能查使用指南 | 常见问题解答">
|
||||
<meta name="twitter:description" content="全能查帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/help">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/help">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "帮助中心 - 全能查使用指南 | 常见问题解答",
|
||||
"description": "全能查帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。",
|
||||
"url": "https://www.quannengcha.com/help",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>帮助中心 - 全能查使用指南 | 常见问题解答</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/help">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/index.html
Normal file
80
public/seo-templates/index.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>全能查官网_个人婚姻状态报告_综合风险排查工具箱</title>
|
||||
|
||||
<meta name="description" content="全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。">
|
||||
<meta name="keywords" content="全能查,婚姻状态核实,风险排查工具,个人风险预警,第三方背调,商业信用评估">
|
||||
|
||||
<meta property="og:title" content="全能查官网_个人婚姻状态报告_综合风险排查工具箱">
|
||||
<meta property="og:description" content="全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="全能查官网_个人婚姻状态报告_综合风险排查工具箱">
|
||||
<meta name="twitter:description" content="全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "全能查官网_个人婚姻状态报告_综合风险排查工具箱",
|
||||
"description": "全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。",
|
||||
"url": "https://www.quannengcha.com",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>全能查官网_个人婚姻状态报告_综合风险排查工具箱</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/inquire-backgroundcheck.html
Normal file
80
public/seo-templates/inquire-backgroundcheck.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>职场背景核验报告_候选人职业风险与竞业核验_全能查</title>
|
||||
|
||||
<meta name="description" content="全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。">
|
||||
<meta name="keywords" content="员工入职背调,职业背景核实,竞业限制评估,职场信用报告,候选人风险筛查">
|
||||
|
||||
<meta property="og:title" content="职场背景核验报告_候选人职业风险与竞业核验_全能查">
|
||||
<meta property="og:description" content="全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/inquire/backgroundcheck">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="职场背景核验报告_候选人职业风险与竞业核验_全能查">
|
||||
<meta name="twitter:description" content="全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/inquire/backgroundcheck">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/inquire/backgroundcheck">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "职场背景核验报告_候选人职业风险与竞业核验_全能查",
|
||||
"description": "全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。",
|
||||
"url": "https://www.quannengcha.com/inquire/backgroundcheck",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>职场背景核验报告_候选人职业风险与竞业核验_全能查</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/inquire/backgroundcheck">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/inquire-companyinfo.html
Normal file
80
public/seo-templates/inquire-companyinfo.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>企业工商信用画像_经营异常与商业风险透视_全能查</title>
|
||||
|
||||
<meta name="description" content="全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。">
|
||||
<meta name="keywords" content="企业信用评估,工商背景核验,商业风险评估,公司经营异常,合作方背景核实">
|
||||
|
||||
<meta property="og:title" content="企业工商信用画像_经营异常与商业风险透视_全能查">
|
||||
<meta property="og:description" content="全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/inquire/companyinfo">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="企业工商信用画像_经营异常与商业风险透视_全能查">
|
||||
<meta name="twitter:description" content="全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/inquire/companyinfo">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/inquire/companyinfo">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "企业工商信用画像_经营异常与商业风险透视_全能查",
|
||||
"description": "全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。",
|
||||
"url": "https://www.quannengcha.com/inquire/companyinfo",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>企业工商信用画像_经营异常与商业风险透视_全能查</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/inquire/companyinfo">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/inquire-consumerFinanceReport.html
Normal file
80
public/seo-templates/inquire-consumerFinanceReport.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>个人履约能力评估_经济风险与收支压力参考_全能查</title>
|
||||
|
||||
<meta name="description" content="全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。">
|
||||
<meta name="keywords" content="履约能力评估,经济风险指数,综合评分波动,资金压力分析,财务健康度">
|
||||
|
||||
<meta property="og:title" content="个人履约能力评估_经济风险与收支压力参考_全能查">
|
||||
<meta property="og:description" content="全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/inquire/consumerFinanceReport">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="个人履约能力评估_经济风险与收支压力参考_全能查">
|
||||
<meta name="twitter:description" content="全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/inquire/consumerFinanceReport">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/inquire/consumerFinanceReport">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "个人履约能力评估_经济风险与收支压力参考_全能查",
|
||||
"description": "全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。",
|
||||
"url": "https://www.quannengcha.com/inquire/consumerFinanceReport",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>个人履约能力评估_经济风险与收支压力参考_全能查</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/inquire/consumerFinanceReport">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/inquire-homeservice.html
Normal file
80
public/seo-templates/inquire-homeservice.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>家政人员背景核实_保姆月嫂司法安全评估_全能查</title>
|
||||
|
||||
<meta name="description" content="全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。">
|
||||
<meta name="keywords" content="保姆背景核验,家政风险筛查,月嫂司法记录,雇佣安全评估,家政人员核验">
|
||||
|
||||
<meta property="og:title" content="家政人员背景核实_保姆月嫂司法安全评估_全能查">
|
||||
<meta property="og:description" content="全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/inquire/homeservice">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="家政人员背景核实_保姆月嫂司法安全评估_全能查">
|
||||
<meta name="twitter:description" content="全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/inquire/homeservice">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/inquire/homeservice">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "家政人员背景核实_保姆月嫂司法安全评估_全能查",
|
||||
"description": "全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。",
|
||||
"url": "https://www.quannengcha.com/inquire/homeservice",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>家政人员背景核实_保姆月嫂司法安全评估_全能查</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/inquire/homeservice">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/inquire-marriage.html
Normal file
80
public/seo-templates/inquire-marriage.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查</title>
|
||||
|
||||
<meta name="description" content="全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。">
|
||||
<meta name="keywords" content="婚前背景报告,恋爱对象风险,情感安全评估,司法记录核验,家庭风险防范">
|
||||
|
||||
<meta property="og:title" content="婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查">
|
||||
<meta property="og:description" content="全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/inquire/marriage">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查">
|
||||
<meta name="twitter:description" content="全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/inquire/marriage">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/inquire/marriage">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查",
|
||||
"description": "全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。",
|
||||
"url": "https://www.quannengcha.com/inquire/marriage",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/inquire/marriage">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/inquire-preloanbackgroundcheck.html
Normal file
80
public/seo-templates/inquire-preloanbackgroundcheck.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查</title>
|
||||
|
||||
<meta name="description" content="全能查提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。">
|
||||
<meta name="keywords" content="综合评分检测,多重履约压力分析,履约能力评估,综合评分优化,个人数据画像">
|
||||
|
||||
<meta property="og:title" content="综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查">
|
||||
<meta property="og:description" content="全能查提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/inquire/preloanbackgroundcheck">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查">
|
||||
<meta name="twitter:description" content="全能查提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/inquire/preloanbackgroundcheck">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/inquire/preloanbackgroundcheck">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查",
|
||||
"description": "全能查提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。",
|
||||
"url": "https://www.quannengcha.com/inquire/preloanbackgroundcheck",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/inquire/preloanbackgroundcheck">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/inquire-riskassessment.html
Normal file
80
public/seo-templates/inquire-riskassessment.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>个人综合风险分析_履约能力画像_多维数据检测_全能查</title>
|
||||
|
||||
<meta name="description" content="全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。">
|
||||
<meta name="keywords" content="个人风险检测,履约能力分析,综合风险指数,信用健康度,个人数据画像">
|
||||
|
||||
<meta property="og:title" content="个人综合风险分析_履约能力画像_多维数据检测_全能查">
|
||||
<meta property="og:description" content="全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/inquire/riskassessment">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="个人综合风险分析_履约能力画像_多维数据检测_全能查">
|
||||
<meta name="twitter:description" content="全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/inquire/riskassessment">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/inquire/riskassessment">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "个人综合风险分析_履约能力画像_多维数据检测_全能查",
|
||||
"description": "全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。",
|
||||
"url": "https://www.quannengcha.com/inquire/riskassessment",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>个人综合风险分析_履约能力画像_多维数据检测_全能查</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/inquire/riskassessment">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/promote.html
Normal file
80
public/seo-templates/promote.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查</title>
|
||||
|
||||
<meta name="description" content="全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。">
|
||||
<meta name="keywords" content="风控系统代理,风险评估平台招商,平台渠道合作,企业服务创业,全能查合伙人">
|
||||
|
||||
<meta property="og:title" content="全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查">
|
||||
<meta property="og:description" content="全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/promote">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查">
|
||||
<meta name="twitter:description" content="全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/promote">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/promote">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查",
|
||||
"description": "全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。",
|
||||
"url": "https://www.quannengcha.com/promote",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/promote">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
public/seo-templates/service.html
Normal file
80
public/seo-templates/service.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>客服中心 - 全能查在线客服 | 技术支持</title>
|
||||
|
||||
<meta name="description" content="全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。">
|
||||
<meta name="keywords" content="客服中心, 在线客服, 技术支持, 问题反馈, 全能查客服">
|
||||
|
||||
<meta property="og:title" content="客服中心 - 全能查在线客服 | 技术支持">
|
||||
<meta property="og:description" content="全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。">
|
||||
<meta property="og:url" content="https://www.quannengcha.com/service">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="客服中心 - 全能查在线客服 | 技术支持">
|
||||
<meta name="twitter:description" content="全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。">
|
||||
<meta name="twitter:url" content="https://www.quannengcha.com/service">
|
||||
|
||||
<link rel="canonical" href="https://www.quannengcha.com/service">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "客服中心 - 全能查在线客服 | 技术支持",
|
||||
"description": "全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。",
|
||||
"url": "https://www.quannengcha.com/service",
|
||||
"mainEntity": {
|
||||
"@type": "Organization",
|
||||
"name": "全能查",
|
||||
"url": "https://www.quannengcha.com/",
|
||||
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>客服中心 - 全能查在线客服 | 技术支持</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="https://www.quannengcha.com/service">点击这里</a></p>
|
||||
</div>
|
||||
<p>全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,67 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/</loc>
|
||||
<loc>https://www.quannengcha.com/</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/agent</loc>
|
||||
<loc>https://www.quannengcha.com/agent</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/help</loc>
|
||||
<loc>https://www.quannengcha.com/help</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/help/guide</loc>
|
||||
<loc>https://www.quannengcha.com/help/guide</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/example</loc>
|
||||
<loc>https://www.quannengcha.com/example</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/service</loc>
|
||||
<loc>https://www.quannengcha.com/service</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.5</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/privacyPolicy</loc>
|
||||
<loc>https://www.quannengcha.com/privacyPolicy</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/userAgreement</loc>
|
||||
<loc>https://www.quannengcha.com/userAgreement</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/agentManageAgreement</loc>
|
||||
<loc>https://www.quannengcha.com/agentManageAgreement</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/agentSerivceAgreement</loc>
|
||||
<loc>https://www.quannengcha.com/agentSerivceAgreement</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://www.zhinengcha.cn/authorization</loc>
|
||||
<loc>https://www.quannengcha.com/authorization</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
|
||||
355
server/README-SEO.md
Normal file
355
server/README-SEO.md
Normal file
@@ -0,0 +1,355 @@
|
||||
# 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/
|
||||
- Google:https://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是否匹配:查看检测器日志
|
||||
|
||||
## 📄 许可
|
||||
|
||||
本方案可自由使用和修改。
|
||||
170
server/crawler-detector.js
Normal file
170
server/crawler-detector.js
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* 爬虫检测模块
|
||||
* 用于识别搜索引擎爬虫和社交媒体爬虫
|
||||
*/
|
||||
|
||||
class CrawlerDetector {
|
||||
constructor() {
|
||||
// 常见搜索引擎爬虫User-Agent列表
|
||||
this.crawlerPatterns = [
|
||||
// 百度爬虫
|
||||
'baiduspider',
|
||||
'baiduspider-mobile',
|
||||
'baiduspider-image',
|
||||
'baiduspider-video',
|
||||
'baiduspider-news',
|
||||
'baiduboxapp',
|
||||
|
||||
// Google爬虫
|
||||
'googlebot',
|
||||
'googlebot-image',
|
||||
'googlebot-news',
|
||||
'googlebot-mobile',
|
||||
'googlebot-video',
|
||||
'google-web-snippet',
|
||||
|
||||
// 360搜索
|
||||
'360spider',
|
||||
'soha-agent',
|
||||
'haosouspider',
|
||||
|
||||
// 搜狗搜索
|
||||
'sogou spider',
|
||||
'sogou news spider',
|
||||
'sogou orion spider',
|
||||
'sogou-blog',
|
||||
|
||||
// 必应
|
||||
'bingbot',
|
||||
'msnbot',
|
||||
|
||||
// 雅虎
|
||||
'slurp',
|
||||
|
||||
// 搜搜
|
||||
'sosospider',
|
||||
'sosoimagespider',
|
||||
|
||||
// 有道
|
||||
'youdaobot',
|
||||
'yodaobot',
|
||||
|
||||
// 头条搜索
|
||||
'bytedance-spider',
|
||||
'toutiaospider',
|
||||
|
||||
// 社交媒体爬虫
|
||||
'facebookexternalhit',
|
||||
'facebookcatalog',
|
||||
'twitterbot',
|
||||
'linkedinbot',
|
||||
'whatsapp',
|
||||
'telegrambot',
|
||||
'viber',
|
||||
'line',
|
||||
|
||||
// 其他常见爬虫
|
||||
'applebot',
|
||||
'semrushbot',
|
||||
'ahrefsbot',
|
||||
'mj12bot',
|
||||
'dotbot',
|
||||
'crawler',
|
||||
'spider',
|
||||
'bot'
|
||||
]
|
||||
|
||||
// 需要检测的头部字段
|
||||
this.crawlerHeaders = ['x-bot', 'x-crawler', 'x-forwarded-for']
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测请求是否来自爬虫
|
||||
* @param {Object} req - HTTP请求对象
|
||||
* @returns {Boolean} 是否为爬虫
|
||||
*/
|
||||
isCrawler(req) {
|
||||
const userAgent = req.headers['user-agent']?.toLowerCase() || ''
|
||||
const headers = req.headers
|
||||
|
||||
// 1. 通过User-Agent检测
|
||||
if (this.checkUserAgent(userAgent)) {
|
||||
console.log(`[CrawlerDetector] 检测到爬虫 UA: ${userAgent}`)
|
||||
return true
|
||||
}
|
||||
|
||||
// 2. 通过特定头部检测
|
||||
if (this.checkHeaders(headers)) {
|
||||
console.log(`[CrawlerDetector] 检测到爬虫 Headers`)
|
||||
return true
|
||||
}
|
||||
|
||||
// 3. 通过IP地址检测(可选)
|
||||
// if (this.checkIP(req.connection.remoteAddress)) {
|
||||
// return true
|
||||
// }
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查User-Agent
|
||||
* @param {String} userAgent
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
checkUserAgent(userAgent) {
|
||||
if (!userAgent) return false
|
||||
|
||||
return this.crawlerPatterns.some(pattern => {
|
||||
return userAgent.includes(pattern.toLowerCase())
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查请求头
|
||||
* @param {Object} headers
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
checkHeaders(headers) {
|
||||
for (const header of this.crawlerHeaders) {
|
||||
const headerValue = headers[header]?.toLowerCase()
|
||||
if (headerValue && (headerValue.includes('bot') || headerValue.includes('crawler'))) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查IP地址是否为已知爬虫IP
|
||||
* @param {String} ip
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
checkIP(ip) {
|
||||
// 这里可以添加已知爬虫IP段的检测
|
||||
// 需要定期更新爬虫IP列表
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取爬虫类型
|
||||
* @param {String} userAgent
|
||||
* @returns {String} 爬虫类型
|
||||
*/
|
||||
getCrawlerType(userAgent) {
|
||||
const ua = userAgent.toLowerCase()
|
||||
|
||||
if (ua.includes('baiduspider')) return 'baidu'
|
||||
if (ua.includes('googlebot')) return 'google'
|
||||
if (ua.includes('bingbot') || ua.includes('msnbot')) return 'bing'
|
||||
if (ua.includes('360spider')) return '360'
|
||||
if (ua.includes('sogou spider')) return 'sogou'
|
||||
if (ua.includes('facebookexternalhit')) return 'facebook'
|
||||
if (ua.includes('twitterbot')) return 'twitter'
|
||||
if (ua.includes('linkedinbot')) return 'linkedin'
|
||||
|
||||
return 'unknown'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CrawlerDetector
|
||||
245
server/generate-seo-templates.cjs
Normal file
245
server/generate-seo-templates.cjs
Normal file
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* SEO模板生成器
|
||||
* 根据 useSEO.js 的页面配置自动生成静态 HTML 模板,供爬虫访问时返回
|
||||
* 配置与 src/composables/useSEO.js 保持一致
|
||||
*
|
||||
* 多站点:通过环境变量 SEO_BASE_URL 指定 canonical/og:url 域名后生成
|
||||
* 例:SEO_BASE_URL=https://www.quannengcha.com node generate-seo-templates.cjs
|
||||
*/
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const BASE_URL = process.env.SEO_BASE_URL || 'https://www.quannengcha.com'
|
||||
|
||||
// 页面 SEO 配置(与 src/composables/useSEO.js 的 routeConfigs 保持一致)
|
||||
const pageSEOConfigs = {
|
||||
'index.html': {
|
||||
title: '全能查官网_个人婚姻状态报告_综合风险排查工具箱',
|
||||
description: '全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。',
|
||||
keywords: '全能查,婚姻状态核实,风险排查工具,个人风险预警,第三方背调,商业信用评估',
|
||||
url: BASE_URL
|
||||
},
|
||||
'agent-system-guide.html': {
|
||||
title: '全能查合作政策指南_合作伙伴权益与结算说明_官方文档',
|
||||
description: '全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。',
|
||||
keywords: '合作伙伴政策,服务费结算,渠道等级说明,业务操作指南,代理系统后台',
|
||||
url: `${BASE_URL}/agent/system-guide`
|
||||
},
|
||||
'inquire-riskassessment.html': {
|
||||
title: '个人综合风险分析_履约能力画像_多维数据检测_全能查',
|
||||
description: '全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。',
|
||||
keywords: '个人风险检测,履约能力分析,综合风险指数,信用健康度,个人数据画像',
|
||||
url: `${BASE_URL}/inquire/riskassessment`
|
||||
},
|
||||
'inquire-companyinfo.html': {
|
||||
title: '企业工商信用画像_经营异常与商业风险透视_全能查',
|
||||
description: '全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。',
|
||||
keywords: '企业信用评估,工商背景核验,商业风险评估,公司经营异常,合作方背景核实',
|
||||
url: `${BASE_URL}/inquire/companyinfo`
|
||||
},
|
||||
'inquire-preloanbackgroundcheck.html': {
|
||||
title: '综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查',
|
||||
description: '全能查提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。',
|
||||
keywords: '综合评分检测,多重履约压力分析,履约能力评估,综合评分优化,个人数据画像',
|
||||
url: `${BASE_URL}/inquire/preloanbackgroundcheck`
|
||||
},
|
||||
'inquire-marriage.html': {
|
||||
title: '婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查',
|
||||
description: '全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。',
|
||||
keywords: '婚前背景报告,恋爱对象风险,情感安全评估,司法记录核验,家庭风险防范',
|
||||
url: `${BASE_URL}/inquire/marriage`
|
||||
},
|
||||
'inquire-backgroundcheck.html': {
|
||||
title: '职场背景核验报告_候选人职业风险与竞业核验_全能查',
|
||||
description: '全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。',
|
||||
keywords: '员工入职背调,职业背景核实,竞业限制评估,职场信用报告,候选人风险筛查',
|
||||
url: `${BASE_URL}/inquire/backgroundcheck`
|
||||
},
|
||||
'inquire-homeservice.html': {
|
||||
title: '家政人员背景核实_保姆月嫂司法安全评估_全能查',
|
||||
description: '全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。',
|
||||
keywords: '保姆背景核验,家政风险筛查,月嫂司法记录,雇佣安全评估,家政人员核验',
|
||||
url: `${BASE_URL}/inquire/homeservice`
|
||||
},
|
||||
'inquire-consumerFinanceReport.html': {
|
||||
title: '个人履约能力评估_经济风险与收支压力参考_全能查',
|
||||
description: '全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。',
|
||||
keywords: '履约能力评估,经济风险指数,综合评分波动,资金压力分析,财务健康度',
|
||||
url: `${BASE_URL}/inquire/consumerFinanceReport`
|
||||
},
|
||||
'agent.html': {
|
||||
title: '全能查代理 - 免费开通代理权限 | 大数据风险报告代理',
|
||||
description: '全能查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。',
|
||||
keywords: '全能查代理, 免费代理, 大数据风险报告代理, 代理权限, 代理收益',
|
||||
url: `${BASE_URL}/agent`
|
||||
},
|
||||
'help.html': {
|
||||
title: '帮助中心 - 全能查使用指南 | 常见问题解答',
|
||||
description: '全能查帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。',
|
||||
keywords: '全能查帮助, 使用指南, 常见问题, 操作教程, 客服支持',
|
||||
url: `${BASE_URL}/help`
|
||||
},
|
||||
'help-guide.html': {
|
||||
title: '使用指南 - 全能查操作教程 | 功能说明',
|
||||
description: '全能查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。',
|
||||
keywords: '使用指南, 操作教程, 功能说明, 快速上手, 全能查教程',
|
||||
url: `${BASE_URL}/help/guide`
|
||||
},
|
||||
'example.html': {
|
||||
title: '示例报告 - 全能查报告展示 | 大数据风险报告样例',
|
||||
description: '全能查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。',
|
||||
keywords: '示例报告, 报告展示, 报告样例, 大数据风险报告, 婚姻查询报告',
|
||||
url: `${BASE_URL}/example`
|
||||
},
|
||||
'service.html': {
|
||||
title: '客服中心 - 全能查在线客服 | 技术支持',
|
||||
description: '全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。',
|
||||
keywords: '客服中心, 在线客服, 技术支持, 问题反馈, 全能查客服',
|
||||
url: `${BASE_URL}/service`
|
||||
},
|
||||
'promote.html': {
|
||||
title: '全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查',
|
||||
description: '全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。',
|
||||
keywords: '风控系统代理,风险评估平台招商,平台渠道合作,企业服务创业,全能查合伙人',
|
||||
url: `${BASE_URL}/promote`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化文案:统一为中文标点,避免乱码
|
||||
*/
|
||||
function normalizeText(str) {
|
||||
if (typeof str !== 'string') return str
|
||||
return str
|
||||
.replace(/\uFFFD/g, '')
|
||||
.replace(/。/g, '。')
|
||||
.replace(/、/g, '、')
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义 HTML 属性值
|
||||
*/
|
||||
function escapeAttr(str) {
|
||||
if (typeof str !== 'string') return ''
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成单页 HTML 模板
|
||||
*/
|
||||
function generateHTMLTemplate(config) {
|
||||
const title = normalizeText(config.title)
|
||||
const description = normalizeText(config.description)
|
||||
const keywords = normalizeText(config.keywords)
|
||||
const structuredData = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebPage',
|
||||
name: title,
|
||||
description: description,
|
||||
url: config.url,
|
||||
mainEntity: {
|
||||
'@type': 'Organization',
|
||||
name: '全能查',
|
||||
url: 'https://www.quannengcha.com/',
|
||||
description: '专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用'
|
||||
}
|
||||
}
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>${escapeAttr(title)}</title>
|
||||
|
||||
<meta name="description" content="${escapeAttr(description)}">
|
||||
<meta name="keywords" content="${escapeAttr(keywords)}">
|
||||
|
||||
<meta property="og:title" content="${escapeAttr(title)}">
|
||||
<meta property="og:description" content="${escapeAttr(description)}">
|
||||
<meta property="og:url" content="${escapeAttr(config.url)}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="全能查">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="${escapeAttr(title)}">
|
||||
<meta name="twitter:description" content="${escapeAttr(description)}">
|
||||
<meta name="twitter:url" content="${escapeAttr(config.url)}">
|
||||
|
||||
<link rel="canonical" href="${escapeAttr(config.url)}">
|
||||
|
||||
<script type="application/ld+json">
|
||||
${JSON.stringify(structuredData, null, 8)}
|
||||
</script>
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="googlebot" content="index, follow">
|
||||
<meta name="baiduspider" content="index, follow">
|
||||
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
.seo-content { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
.redirect-notice { background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 10px; margin: 20px 0; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="seo-content">
|
||||
<h1>${escapeAttr(title)}</h1>
|
||||
<div class="redirect-notice">
|
||||
<p>正在跳转到完整版网站...</p>
|
||||
<p>如果浏览器没有自动跳转,请 <a href="${escapeAttr(config.url)}">点击这里</a></p>
|
||||
</div>
|
||||
<p>${escapeAttr(description)}</p>
|
||||
<section>
|
||||
<h2>关于全能查</h2>
|
||||
<p>全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>核心服务</h2>
|
||||
<ul>
|
||||
<li>个人综合风险分析与履约能力画像</li>
|
||||
<li>企业工商信用画像与商业风险透视</li>
|
||||
<li>婚前综合背景了解与情感安全风险评估</li>
|
||||
<li>职场背景核验与入职背调</li>
|
||||
<li>家政人员背景核实与安全评估</li>
|
||||
<li>个人履约能力评估与经济风险分析</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
}
|
||||
|
||||
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}`)
|
||||
console.log(`💡 配置与 useSEO.js 一致,当前域名: ${BASE_URL}`)
|
||||
}
|
||||
|
||||
main()
|
||||
179
server/middleware.js
Normal file
179
server/middleware.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* 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
|
||||
|
||||
// 路由到模板的映射(与 useSEO.js 及 generate-seo-templates.cjs 保持一致;子路径放前面以优先精确匹配)
|
||||
this.routeTemplateMap = {
|
||||
'/': 'index.html',
|
||||
'/agent/system-guide': 'agent-system-guide.html',
|
||||
'/inquire/riskassessment': 'inquire-riskassessment.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',
|
||||
'/inquire/consumerFinanceReport': 'inquire-consumerFinanceReport.html',
|
||||
'/agent': 'agent.html',
|
||||
'/help/guide': 'help-guide.html',
|
||||
'/help': 'help.html',
|
||||
'/example': 'example.html',
|
||||
'/service': 'service.html',
|
||||
'/promote': 'promote.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
|
||||
419
server/nginx-www.quannengcha.com.conf
Normal file
419
server/nginx-www.quannengcha.com.conf
Normal file
@@ -0,0 +1,419 @@
|
||||
# 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;
|
||||
}
|
||||
27
server/package.json
Normal file
27
server/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "tydata-seo-server",
|
||||
"version": "1.0.0",
|
||||
"description": "SPA SEO 优化 - 爬虫检测与静态 HTML 回退,与 useSEO.js 同步",
|
||||
"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"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"compression": "^1.7.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.0.1"
|
||||
}
|
||||
}
|
||||
36
server/server-example-express.js
Normal file
36
server/server-example-express.js
Normal file
@@ -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
|
||||
112
server/test-crawler-detection.js
Normal file
112
server/test-crawler-detection.js
Normal file
@@ -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)
|
||||
178
server/test-seo.js
Normal file
178
server/test-seo.js
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* 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 标题关键词(与 useSEO.js 一致,天远数据)
|
||||
const ROUTES = [
|
||||
{ path: '/', titleKeyword: '天远数据' },
|
||||
{ path: '/agent', titleKeyword: '天远数据代理' },
|
||||
{ path: '/help', titleKeyword: '天远数据帮助中心' },
|
||||
{ path: '/inquire/personalData', titleKeyword: '个人综合风险报告' },
|
||||
{ path: '/agent/promote', titleKeyword: '推广码' },
|
||||
{ path: '/historyQuery', 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(/<title[^>]*>([^<]+)<\/title>/i)
|
||||
return match ? match[1].trim() : null
|
||||
}
|
||||
|
||||
function hasMetaDescription(html) {
|
||||
return /<meta\s+name=["']description["']\s+content=["']/i.test(html)
|
||||
}
|
||||
|
||||
function isSEOTemplate(html) {
|
||||
return (
|
||||
/<meta\s+name=["']description["']/i.test(html) &&
|
||||
/<meta\s+name=["']keywords["']/i.test(html) &&
|
||||
/<link\s+rel=["']canonical["']/i.test(html)
|
||||
)
|
||||
}
|
||||
|
||||
async function runTest(route, titleKeyword) {
|
||||
const url = BASE_URL + route
|
||||
const results = { route, crawler: null, normal: null }
|
||||
|
||||
// 1. 爬虫请求
|
||||
try {
|
||||
const crawlerRes = await request(url, 'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)')
|
||||
const title = extractTitle(crawlerRes.body)
|
||||
const seoHeader = crawlerRes.headers['x-seomiddleware']
|
||||
|
||||
results.crawler = {
|
||||
status: crawlerRes.statusCode,
|
||||
title,
|
||||
hasSEOMeta: hasMetaDescription(crawlerRes.body),
|
||||
isSEOTemplate: isSEOTemplate(crawlerRes.body),
|
||||
seoHeader: seoHeader || '(无)'
|
||||
}
|
||||
|
||||
if (crawlerRes.statusCode !== 200) {
|
||||
results.crawler.error = `HTTP ${crawlerRes.statusCode}`
|
||||
} else if (!title || !title.includes(titleKeyword)) {
|
||||
results.crawler.error = `标题不匹配,期望含「${titleKeyword}」,实际: ${title || '未找到'}`
|
||||
} else if (!results.crawler.isSEOTemplate) {
|
||||
results.crawler.error = '响应中缺少完整 SEO 标签(description/keywords/canonical)'
|
||||
}
|
||||
} catch (e) {
|
||||
results.crawler = { error: e.message || String(e) }
|
||||
}
|
||||
|
||||
// 2. 普通用户请求(仅验证能正常返回)
|
||||
try {
|
||||
const normalRes = await request(url, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
|
||||
results.normal = {
|
||||
status: normalRes.statusCode,
|
||||
bodyLength: normalRes.body.length
|
||||
}
|
||||
if (normalRes.statusCode !== 200) {
|
||||
results.normal.error = `HTTP ${normalRes.statusCode}`
|
||||
}
|
||||
} catch (e) {
|
||||
results.normal = { error: e.message || String(e) }
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
function printResult(results) {
|
||||
const { route, crawler, normal } = results
|
||||
|
||||
console.log(`\n📍 路由: ${route}`)
|
||||
console.log('─'.repeat(60))
|
||||
|
||||
const crawlerOk = crawler && !crawler.error && crawler.status === 200 && crawler.isSEOTemplate
|
||||
if (crawlerOk) {
|
||||
console.log(' 爬虫请求: ✓ 通过')
|
||||
console.log(` 标题: ${crawler.title}`)
|
||||
console.log(` 响应头: X-SEOMiddleware = ${crawler.seoHeader}`)
|
||||
} else {
|
||||
console.log(' 爬虫请求: ✗ 未通过')
|
||||
if (crawler && crawler.error) console.log(` 原因: ${crawler.error}`)
|
||||
else if (crawler) console.log(` 状态: ${crawler.status}, 标题: ${crawler.title || '无'}`)
|
||||
else console.log(' 请求失败')
|
||||
}
|
||||
|
||||
const normalOk = normal && !normal.error && normal.status === 200
|
||||
if (normalOk) {
|
||||
console.log(' 普通用户: ✓ 正常 (SPA)')
|
||||
} else {
|
||||
console.log(' 普通用户: ✗ 异常')
|
||||
if (normal && normal.error) console.log(` 原因: ${normal.error}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('='.repeat(60))
|
||||
console.log('SEO 端到端检测')
|
||||
console.log('='.repeat(60))
|
||||
console.log(`目标地址: ${BASE_URL}`)
|
||||
console.log('若服务器未启动,请先执行: npm run start')
|
||||
console.log('')
|
||||
|
||||
let allPass = true
|
||||
|
||||
for (const r of ROUTES) {
|
||||
try {
|
||||
const results = await runTest(r.path, r.titleKeyword)
|
||||
printResult(results)
|
||||
|
||||
const crawlerOk = results.crawler && !results.crawler.error && results.crawler.isSEOTemplate
|
||||
const normalOk = results.normal && !results.normal.error && results.normal.status === 200
|
||||
if (!crawlerOk || !normalOk) allPass = false
|
||||
} catch (e) {
|
||||
console.log(`\n📍 路由: ${r.path}`)
|
||||
console.log(' 错误:', e.message)
|
||||
allPass = false
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(60))
|
||||
if (allPass) {
|
||||
console.log('✓ 全部检测通过:爬虫获得 SEO 模板,普通用户获得 SPA')
|
||||
} else {
|
||||
console.log('✗ 部分检测未通过,请检查服务器与模板配置')
|
||||
}
|
||||
console.log('='.repeat(60))
|
||||
|
||||
process.exit(allPass ? 0 : 1)
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('检测失败:', err)
|
||||
process.exit(1)
|
||||
})
|
||||
211
server/如何检测.md
Normal file
211
server/如何检测.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# 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** 再请求一遍,确认仍是 200(SPA 正常)
|
||||
|
||||
全部通过即说明:爬虫拿到的是 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-8,CMD 默认是 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
|
||||
# 方式 2:PowerShell 下指定输出编码
|
||||
[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 请求 | 返回 200,HTML 内含完整 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 检测。
|
||||
56
server/宝塔Nginx-SEO部署说明.md
Normal file
56
server/宝塔Nginx-SEO部署说明.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 宝塔环境 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`**(需先启动本地服务)。
|
||||
50
server/部署说明-tianyuandb.md
Normal file
50
server/部署说明-tianyuandb.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# 天远数据 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 已生效。
|
||||
@@ -127,6 +127,7 @@ const router = useRouter();
|
||||
const show = defineModel("show");
|
||||
import { useCascaderAreaData } from "@vant/area-data";
|
||||
import { showToast } from "vant"; // 引入 showToast 方法
|
||||
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
|
||||
const emit = defineEmits(); // 确保 emit 可以正确使用
|
||||
const props = defineProps({
|
||||
isSelf: {
|
||||
@@ -139,6 +140,7 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
const { isSelf, userName } = toRefs(props);
|
||||
const { runWithCaptcha } = useAliyunCaptcha();
|
||||
const form = ref({
|
||||
referrer: "",
|
||||
region: "",
|
||||
@@ -173,20 +175,22 @@ const getSmsCode = async () => {
|
||||
|
||||
loadingSms.value = true;
|
||||
|
||||
const { data, error } = await useApiFetch("auth/sendSms")
|
||||
.post({ mobile: form.value.mobile, actionType: "agentApply" })
|
||||
.json();
|
||||
|
||||
loadingSms.value = false;
|
||||
|
||||
if (data.value && !error.value) {
|
||||
if (data.value.code === 200) {
|
||||
showToast({ message: "获取成功" });
|
||||
startCountdown(); // 启动倒计时
|
||||
} else {
|
||||
showToast(data.value.msg);
|
||||
// 使用滑块验证码保护发送短信接口
|
||||
runWithCaptcha(
|
||||
(captchaVerifyParam) =>
|
||||
useApiFetch("auth/sendSms")
|
||||
.post({ mobile: form.value.mobile, actionType: "agentApply", captchaVerifyParam })
|
||||
.json(),
|
||||
(res) => {
|
||||
loadingSms.value = false;
|
||||
if (res.code === 200) {
|
||||
showToast({ message: "获取成功" });
|
||||
startCountdown(); // 启动倒计时
|
||||
} else {
|
||||
showToast(res.msg || "获取验证码失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
let timer = null;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useUserStore } from "@/stores/userStore";
|
||||
import { showToast } from "vant";
|
||||
import useApiFetch from "@/composables/useApiFetch";
|
||||
import { registerByInviteCode } from "@/api/agent";
|
||||
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
|
||||
|
||||
const emit = defineEmits(['register-success'])
|
||||
const router = useRouter();
|
||||
@@ -14,6 +15,7 @@ const route = useRoute();
|
||||
const dialogStore = useDialogStore();
|
||||
const agentStore = useAgentStore();
|
||||
const userStore = useUserStore();
|
||||
const { runWithCaptcha } = useAliyunCaptcha();
|
||||
const appName = import.meta.env.VITE_APP_NAME || '全能查';
|
||||
const phoneNumber = ref("");
|
||||
const verificationCode = ref("");
|
||||
@@ -80,26 +82,31 @@ async function sendVerificationCode() {
|
||||
showToast({ message: "请先输入邀请码" });
|
||||
return;
|
||||
}
|
||||
const actionType = hasAccount.value ? "bindMobile" : "agentApply";
|
||||
const { data, error } = await useApiFetch("auth/sendSms")
|
||||
.post({ mobile: phoneNumber.value, actionType })
|
||||
.json();
|
||||
|
||||
if (data.value && !error.value) {
|
||||
if (data.value.code === 200) {
|
||||
showToast({ message: "获取成功" });
|
||||
startCountdown();
|
||||
// 聚焦到验证码输入框
|
||||
nextTick(() => {
|
||||
const verificationCodeInput = document.getElementById('registerVerificationCode');
|
||||
if (verificationCodeInput) {
|
||||
verificationCodeInput.focus();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showToast(data.value.msg);
|
||||
const actionType = hasAccount.value ? "bindMobile" : "agentApply";
|
||||
|
||||
// 使用滑块验证码保护发送短信接口
|
||||
runWithCaptcha(
|
||||
(captchaVerifyParam) =>
|
||||
useApiFetch("auth/sendSms")
|
||||
.post({ mobile: phoneNumber.value, actionType, captchaVerifyParam })
|
||||
.json(),
|
||||
(res) => {
|
||||
if (res.code === 200) {
|
||||
showToast({ message: "获取成功" });
|
||||
startCountdown();
|
||||
// 聚焦到验证码输入框
|
||||
nextTick(() => {
|
||||
const verificationCodeInput = document.getElementById('registerVerificationCode');
|
||||
if (verificationCodeInput) {
|
||||
verificationCodeInput.focus();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showToast(res.msg || "获取验证码失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function startCountdown() {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<script setup>
|
||||
import { ref, computed, nextTick } from "vue";
|
||||
import { useDialogStore } from "@/stores/dialogStore";
|
||||
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
|
||||
|
||||
const emit = defineEmits(['bind-success'])
|
||||
const router = useRouter();
|
||||
const dialogStore = useDialogStore();
|
||||
const agentStore = useAgentStore();
|
||||
const userStore = useUserStore();
|
||||
const { runWithCaptcha } = useAliyunCaptcha();
|
||||
const appName = import.meta.env.VITE_APP_NAME || '全能查';
|
||||
const phoneNumber = ref("");
|
||||
const verificationCode = ref("");
|
||||
@@ -37,25 +39,29 @@ async function sendVerificationCode() {
|
||||
showToast({ message: "请输入有效的手机号" });
|
||||
return;
|
||||
}
|
||||
const { data, error } = await useApiFetch("auth/sendSms")
|
||||
.post({ mobile: phoneNumber.value, actionType: "bindMobile" })
|
||||
.json();
|
||||
|
||||
if (data.value && !error.value) {
|
||||
if (data.value.code === 200) {
|
||||
showToast({ message: "获取成功" });
|
||||
startCountdown();
|
||||
// 聚焦到验证码输入框
|
||||
nextTick(() => {
|
||||
const verificationCodeInput = document.getElementById('bindPhoneVerificationCode');
|
||||
if (verificationCodeInput) {
|
||||
verificationCodeInput.focus();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showToast(data.value.msg);
|
||||
// 使用滑块验证码保护发送短信接口
|
||||
runWithCaptcha(
|
||||
(captchaVerifyParam) =>
|
||||
useApiFetch("auth/sendSms")
|
||||
.post({ mobile: phoneNumber.value, actionType: "bindMobile", captchaVerifyParam })
|
||||
.json(),
|
||||
(res) => {
|
||||
if (res.code === 200) {
|
||||
showToast({ message: "获取成功" });
|
||||
startCountdown();
|
||||
// 聚焦到验证码输入框
|
||||
nextTick(() => {
|
||||
const verificationCodeInput = document.getElementById('bindPhoneVerificationCode');
|
||||
if (verificationCodeInput) {
|
||||
verificationCodeInput.focus();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showToast(res.msg || "获取验证码失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function startCountdown() {
|
||||
|
||||
@@ -6,11 +6,14 @@ import { useAgentStore } from "@/stores/agentStore";
|
||||
import { useUserStore } from "@/stores/userStore";
|
||||
import { showToast } from "vant";
|
||||
import { realNameAuth } from "@/api/agent";
|
||||
import useApiFetch from "@/composables/useApiFetch";
|
||||
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
|
||||
|
||||
const router = useRouter();
|
||||
const dialogStore = useDialogStore();
|
||||
const agentStore = useAgentStore();
|
||||
const userStore = useUserStore();
|
||||
const { runWithCaptcha } = useAliyunCaptcha();
|
||||
// 表单数据
|
||||
const realName = ref("");
|
||||
const idCard = ref("");
|
||||
@@ -59,18 +62,22 @@ async function sendVerificationCode() {
|
||||
showToast({ message: "请输入有效的手机号" });
|
||||
return;
|
||||
}
|
||||
const { data, error } = await useApiFetch("auth/sendSms")
|
||||
.post({ mobile: phoneNumber.value, actionType: "realName" })
|
||||
.json();
|
||||
|
||||
if (data.value && !error.value) {
|
||||
if (data.value.code === 200) {
|
||||
showToast({ message: "获取成功" });
|
||||
startCountdown();
|
||||
} else {
|
||||
showToast(data.value.msg);
|
||||
// 使用滑块验证码保护发送短信接口
|
||||
runWithCaptcha(
|
||||
(captchaVerifyParam) =>
|
||||
useApiFetch("auth/sendSms")
|
||||
.post({ mobile: phoneNumber.value, actionType: "realName", captchaVerifyParam })
|
||||
.json(),
|
||||
(res) => {
|
||||
if (res.code === 200) {
|
||||
showToast({ message: "获取成功" });
|
||||
startCountdown();
|
||||
} else {
|
||||
showToast(res.msg || "获取验证码失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function startCountdown() {
|
||||
|
||||
@@ -11,7 +11,7 @@ export function useSEO() {
|
||||
"全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。",
|
||||
keywords:
|
||||
"全能查,婚姻状态核实,风险排查工具,个人风险预警,第三方背调,商业信用评估",
|
||||
url: "https://www.zhinengcha.cn",
|
||||
url: "https://www.quannengcha.com",
|
||||
};
|
||||
|
||||
// 页面SEO配置
|
||||
@@ -137,7 +137,7 @@ export function useSEO() {
|
||||
mainEntity: {
|
||||
"@type": "Organization",
|
||||
name: "全能查",
|
||||
url: "https://www.zhinengcha.cn/",
|
||||
url: "https://www.quannengcha.com/",
|
||||
description:
|
||||
"专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用",
|
||||
},
|
||||
@@ -251,7 +251,7 @@ export function useSEO() {
|
||||
|
||||
updateSEO({
|
||||
...config,
|
||||
url: `https://www.zhinengcha.cn${currentPath}`,
|
||||
url: `https://www.quannengcha.com${currentPath}`,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -509,7 +509,7 @@ router.afterEach((to) => {
|
||||
const seoConfig = {
|
||||
title: `${to.meta.title} - 全能查`,
|
||||
description: `全能查${to.meta.title}页面,提供专业的大数据风险管控服务。`,
|
||||
url: `https://www.zhinengcha.cn${to.path}`,
|
||||
url: `https://www.quannengcha.com${to.path}`,
|
||||
};
|
||||
updateSEO(seoConfig);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ onMounted(() => {
|
||||
title: '404 - 页面未找到 | 全能查',
|
||||
description: '抱歉,您访问的页面不存在。全能查专业大数据风险管控平台,提供大数据风险报告查询、婚姻状况查询、个人信用评估等服务。',
|
||||
keywords: '404, 页面未找到, 全能查, 大数据风险管控',
|
||||
url: 'https://www.zhinengcha.cn/404'
|
||||
url: 'https://www.quannengcha.com/404'
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
256
微信授权流程设计文档.md
256
微信授权流程设计文档.md
@@ -1,256 +0,0 @@
|
||||
# 微信 H5 授权流程重构 - 设计文档
|
||||
|
||||
## 📋 核心业务需求
|
||||
|
||||
在微信 H5 环境中,**整个应用在没有有效 token 时,都需要进行微信授权登录**。授权完成后,用户应该被重定向回他们尝试访问的原始页面。
|
||||
|
||||
---
|
||||
|
||||
## 🔄 流程设计
|
||||
|
||||
### **完整的授权流程图**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 用户在微信中访问任意页面(无 token) │
|
||||
└──────────────────┬──────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 路由守卫检测:微信 + 无 token │
|
||||
│ → 保存目标路由到 authStore.pendingRoute │
|
||||
│ → 生成微信授权 URL │
|
||||
│ → window.location.href = 授权 URL (不调用 next()) │
|
||||
└──────────────────┬──────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 跳转到微信授权页面 │
|
||||
│ https://open.weixin.qq.com/connect/oauth2/authorize?... │
|
||||
└──────────────────┬──────────────────────────────────────────┘
|
||||
│
|
||||
┌─────────┴─────────┐
|
||||
│ 用户点击"同意" │
|
||||
└────────┬──────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 微信回调:redirectUri?code=xxx&state=yyy │
|
||||
│ 浏览器重新加载应用,URL 中包含 code/state 参数 │
|
||||
└──────────────────┬──────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ App.vue onMounted 检测到 code + state 参数 │
|
||||
│ → 调用 handleWeixinAuthCallback(code) │
|
||||
└──────────────────┬──────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 1. 调用后端接口 /user/wxh5Auth 交换 token │
|
||||
│ 2. 保存 token 到 localStorage │
|
||||
│ 3. 清理 URL 中的 code/state 参数 │
|
||||
│ 4. 获取用户信息 │
|
||||
│ 5. 标记授权完成 authStore.completeWeixinAuth() │
|
||||
└──────────────────┬──────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 获取 pendingRoute,重定向回原始页面 │
|
||||
│ router.replace(pendingRoute) │
|
||||
│ 如果没有 pendingRoute,重定向到首页 "/" │
|
||||
└──────────────────┬──────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ✅ 授权完成,用户看到原始页面 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 关键文件修改
|
||||
|
||||
### **1. `src/router/index.js` - 路由守卫**
|
||||
|
||||
**关键变化:**
|
||||
- 检测到 **微信 + 无 token** 的情况
|
||||
- **直接发起授权**(调用 `window.location.href`)
|
||||
- **不调用 `next()`**,完全停止导航
|
||||
- 授权 URL 中的 redirectUri 指向当前页面(清理旧的 code/state 参数)
|
||||
|
||||
**代码片段:**
|
||||
```javascript
|
||||
if (isWeChat.value && !isAuthenticated && !isTokenExpired) {
|
||||
// 保存目标路由
|
||||
authStore.startWeixinAuth(to);
|
||||
|
||||
// 生成授权 URL
|
||||
const appId = import.meta.env.VITE_WECHAT_APP_ID;
|
||||
const url = new URL(window.location.href);
|
||||
const params = new URLSearchParams(url.search);
|
||||
params.delete("code");
|
||||
params.delete("state");
|
||||
const cleanUrl = `${url.origin}${url.pathname}${params.toString() ? "?" + params.toString() : ""}`;
|
||||
const redirectUri = encodeURIComponent(cleanUrl);
|
||||
const weixinAuthUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=snsapi_base#wechat_redirect`;
|
||||
|
||||
// 直接跳转,不调用 next()
|
||||
window.location.href = weixinAuthUrl;
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### **2. `src/App.vue` - 授权回调处理**
|
||||
|
||||
**关键职责:**
|
||||
1. **检测回调**:读取 URL 中的 code/state 参数
|
||||
2. **处理回调**:调用 `/user/wxh5Auth` 交换 token
|
||||
3. **恢复导航**:使用保存的 pendingRoute 重定向用户
|
||||
|
||||
**核心函数:`handleWeixinAuthCallback(code)`**
|
||||
```javascript
|
||||
const handleWeixinAuthCallback = async (code) => {
|
||||
// 1. 交换 token
|
||||
const { data, error } = await useApiFetch("/user/wxh5Auth").post({ code }).json();
|
||||
|
||||
// 2. 保存 token
|
||||
localStorage.setItem("token", data.value.data.accessToken);
|
||||
localStorage.setItem("refreshAfter", data.value.data.refreshAfter);
|
||||
localStorage.setItem("accessExpire", data.value.data.accessExpire);
|
||||
|
||||
// 3. 清理 URL
|
||||
const url = new URL(window.location.href);
|
||||
const params = new URLSearchParams(url.search);
|
||||
params.delete("code");
|
||||
params.delete("state");
|
||||
window.history.replaceState({}, "", newUrl);
|
||||
|
||||
// 4. 获取用户信息
|
||||
await userStore.fetchUserInfo();
|
||||
|
||||
// 5. 标记授权完成
|
||||
authStore.completeWeixinAuth();
|
||||
|
||||
// 6. 重定向回 pendingRoute
|
||||
const pendingRoute = authStore.pendingRoute;
|
||||
await router.replace(pendingRoute || "/");
|
||||
};
|
||||
```
|
||||
|
||||
### **3. `src/stores/authStore.js` - 授权状态管理**
|
||||
|
||||
**关键方法:**
|
||||
|
||||
| 方法 | 作用 |
|
||||
|------|------|
|
||||
| `startWeixinAuth(targetRoute)` | 开始授权,保存目标路由 |
|
||||
| `completeWeixinAuth()` | 标记授权完成 |
|
||||
| `clearPendingRoute()` | 清除待处理路由 |
|
||||
| `resetAuthState()` | 重置所有授权状态 |
|
||||
| `restoreFromStorage()` | 页面刷新后恢复状态 |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 核心特性
|
||||
|
||||
### **1. 同步流程控制**
|
||||
- ❌ **不使用** `watch` 监听 state 的变化
|
||||
- ❌ **不使用** 异步的 route guard + next() 来触发授权
|
||||
- ✅ **直接** 在 route guard 中调用 `window.location.href` 发起授权
|
||||
|
||||
**为什么?**
|
||||
- Watch 是异步的,可能被路由完成打断
|
||||
- next() 后可能路由已经切换,导致授权流程混乱
|
||||
- 直接跳转 URL 更加可靠和同步
|
||||
|
||||
### **2. 状态持久化**
|
||||
- 授权开始时保存到 localStorage
|
||||
- 页面刷新时自动恢复状态
|
||||
- 防止超时(30秒)导致的无限授权循环
|
||||
|
||||
### **3. URL 参数清理**
|
||||
- 每次发起授权前,都清理 URL 中旧的 code/state 参数
|
||||
- 防止参数被重复编码进 redirectUri
|
||||
- 微信回调时才注入新的 code/state
|
||||
|
||||
### **4. 目标页面恢复**
|
||||
- 路由守卫保存用户尝试访问的页面
|
||||
- 授权完成后自动重定向到该页面
|
||||
- 用户无感知的完整授权体验
|
||||
|
||||
---
|
||||
|
||||
## 🔐 场景处理
|
||||
|
||||
### **场景 1:无 token + 访问开放页面**
|
||||
```
|
||||
用户访问 "/" → 微信检测无 token → 发起授权 → 授权完成后回到首页
|
||||
```
|
||||
|
||||
### **场景 2:无 token + 访问推广链接**
|
||||
```
|
||||
用户访问 "/agent/promotionInquire/abc123"
|
||||
→ 微信检测无 token
|
||||
→ 保存 pendingRoute = "/agent/promotionInquire/abc123"
|
||||
→ 发起授权
|
||||
→ 授权完成后回到 "/agent/promotionInquire/abc123"
|
||||
```
|
||||
|
||||
### **场景 3:有效 token + 访问任意页面**
|
||||
```
|
||||
用户有 token 且未过期 → 路由守卫放行 → 直接加载页面,无授权
|
||||
```
|
||||
|
||||
### **场景 4:Token 过期 + 访问需登录页面**
|
||||
```
|
||||
用户在非微信环境 → 检测到 token 过期 → 跳转登录页面
|
||||
```
|
||||
|
||||
### **场景 5:授权超时**
|
||||
```
|
||||
用户授权流程中,30 秒内未完成 → 自动重置状态 → 页面刷新时重新授权
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题排查
|
||||
|
||||
### **Q1:为什么授权后没有跳到原页面?**
|
||||
**A:** 检查 authStore 中是否有 pendingRoute
|
||||
```javascript
|
||||
console.log('pendingRoute:', authStore.pendingRoute);
|
||||
```
|
||||
|
||||
### **Q2:为什么一直在授权页面循环?**
|
||||
**A:** 可能是授权回调处理失败。检查:
|
||||
1. 后端 `/user/wxh5Auth` 接口是否正确返回 token
|
||||
2. Token 是否正确保存到 localStorage
|
||||
3. URL 中的 code/state 是否正确清理
|
||||
|
||||
### **Q3:为什么刷新页面后授权状态丢失?**
|
||||
**A:** authStore.restoreFromStorage() 应该在 onMounted 中被调用。检查:
|
||||
```javascript
|
||||
authStore.restoreFromStorage(); // 这行很重要!
|
||||
```
|
||||
|
||||
### **Q4:在 PC 上测试,为什么无法触发授权?**
|
||||
**A:** 授权只在微信环境中触发(isWeChat.value === true)。在 PC 上:
|
||||
- 访问需登录的页面 → 跳转登录页
|
||||
- 访问开放页面 → 正常加载
|
||||
|
||||
---
|
||||
|
||||
## 📝 总结
|
||||
|
||||
这个重构的核心思想是:
|
||||
1. **路由守卫 = 决策者**:检测到需要授权就立即发起
|
||||
2. **App.vue = 处理器**:处理授权回调和状态恢复
|
||||
3. **AuthStore = 状态管理**:保存和恢复授权相关的状态
|
||||
4. **同步流程 = 高可靠性**:避免异步竞态条件
|
||||
|
||||
通过这个设计,微信授权流程变得:
|
||||
- ✅ 清晰易懂
|
||||
- ✅ 可靠稳定
|
||||
- ✅ 易于测试和调试
|
||||
- ✅ 完整的用户体验
|
||||
@@ -1,121 +0,0 @@
|
||||
# 微信授权重定向问题分析与修复
|
||||
|
||||
## 问题描述
|
||||
微信授权回调成功后,虽然 `pendingRoute` 有正确的值,回调成功也能跳转到应该到达的页面(如 `promotionInquire`),但在加载该页面后,又会自动跳转到首页。
|
||||
|
||||
## 根本原因分析
|
||||
|
||||
### 问题 1: pendingRoute 清除时序错误 ❌
|
||||
**位置**: `src/App.vue` 第 69-72 行
|
||||
|
||||
**原始代码**:
|
||||
```javascript
|
||||
if (pendingRoute) {
|
||||
authStore.clearPendingRoute(); // ❌ 先清除
|
||||
await router.replace(pendingRoute); // 用已清空的 null 值跳转
|
||||
}
|
||||
```
|
||||
|
||||
**问题**:
|
||||
- `clearPendingRoute()` 将 `authStore.pendingRoute` 设为 `null`
|
||||
- 之后 `router.replace(pendingRoute)` 使用的是已清空的 `null` 值
|
||||
- 导致实际跳转到 `undefined` 而非目标路由
|
||||
|
||||
**修复**: 先跳转再清除 ✅
|
||||
|
||||
### 问题 2: 路由守卫重复授权防护缺失 ❌
|
||||
**位置**: `src/router/index.js` 第 428-444 行
|
||||
|
||||
**问题**:
|
||||
- 当用户在授权完成后,路由守卫再次执行时
|
||||
- 如果 `isWeChat.value && !isAuthenticated` 条件满足
|
||||
- 会重新触发授权流程,导致页面跳转
|
||||
|
||||
**原因**:
|
||||
- `authStore.isWeixinAuthing` 和 `authStore.weixinAuthComplete` 状态未被路由守卫检查
|
||||
- 虽然 token 已保存,但守卫仍可能因某些时序问题再次触发授权
|
||||
|
||||
**修复**: 在路由守卫中增加授权状态检查 ✅
|
||||
|
||||
### 问题 3: localStorage 同步问题
|
||||
**位置**: `src/stores/authStore.js`
|
||||
|
||||
**问题**:
|
||||
- 清除 `pendingRoute` 时,可能只清除内存状态,localStorage 可能残留数据
|
||||
- 页面刷新时恢复的数据可能不完整
|
||||
|
||||
**修复**: 确保内存和 localStorage 同步清除 ✅
|
||||
|
||||
## 修复清单
|
||||
|
||||
### ✅ 修复 1: App.vue 中的时序问题
|
||||
```javascript
|
||||
if (pendingRoute) {
|
||||
// ✅ 先跳转
|
||||
await router.replace(pendingRoute);
|
||||
// ✅ 再清除
|
||||
authStore.clearPendingRoute();
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ 修复 2: 路由守卫的防护检查
|
||||
在路由守卫中增加:
|
||||
```javascript
|
||||
if (isWeChat.value && !isAuthenticated && !isTokenExpired) {
|
||||
// ✨ 新增:检查是否正在授权或已完成授权
|
||||
if (authStore.isWeixinAuthing || authStore.weixinAuthComplete) {
|
||||
console.warn("⚠️ WeChat auth already in progress or completed");
|
||||
NProgress.done();
|
||||
next();
|
||||
return;
|
||||
}
|
||||
// ... 继续原有逻辑
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ 修复 3: authStore 中的日志和同步
|
||||
增强 `clearPendingRoute()` 和 `restoreFromStorage()` 方法的日志记录和错误处理。
|
||||
|
||||
### ✅ 修复 4: PromotionInquire.vue 中的延迟处理
|
||||
添加延迟以确保页面完全加载后再进行任何路由跳转:
|
||||
```javascript
|
||||
function isFinishPayment() {
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
let orderNo = query.get("out_trade_no");
|
||||
if (orderNo) {
|
||||
// ✨ 延迟 100ms 确保页面加载完成
|
||||
setTimeout(() => {
|
||||
router.push({ path: "/report", query: { orderNo } });
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 调试建议
|
||||
|
||||
### 观察日志的关键点:
|
||||
1. **微信授权开始**: 看是否出现 "Triggering WeChat auth from route guard"
|
||||
2. **Token 保存**: 看是否出现 "✅ Token saved successfully"
|
||||
3. **用户信息加载**: 看 "✅ User info fetched" 是否成功
|
||||
4. **pendingRoute 获取**: 看 "🎯 pendingRoute:" 后面的值
|
||||
5. **导航执行**: 看 "🚀 Navigating to pendingRoute:" 和 "✅ Navigated to pendingRoute"
|
||||
6. **是否重复授权**: 看是否出现 "⚠️ WeChat auth already in progress"
|
||||
|
||||
### 测试步骤:
|
||||
1. 在微信中打开推广链接: `https://xxx.com/agent/promotionInquire/abc123`
|
||||
2. 观察控制台日志,确保看到上述所有成功日志
|
||||
3. 验证最终页面是 `promotionInquire` 而非首页
|
||||
|
||||
## 修复文件列表
|
||||
- ✅ `src/App.vue` - 修复 pendingRoute 时序问题
|
||||
- ✅ `src/router/index.js` - 增强路由守卫防护
|
||||
- ✅ `src/stores/authStore.js` - 改进日志和同步
|
||||
- ✅ `src/views/PromotionInquire.vue` - 添加延迟处理
|
||||
|
||||
## 总结
|
||||
这个问题是由多个时序和状态管理问题联合造成的:
|
||||
1. pendingRoute 被过早清除导致跳转失败
|
||||
2. 路由守卫缺少防护措施可能重复授权
|
||||
3. 状态同步不完整可能导致恢复失败
|
||||
|
||||
通过修复这些问题,应该能够确保微信授权后正确重定向到目标页面。
|
||||
456
阿里云验证码接入.md
456
阿里云验证码接入.md
@@ -1,456 +0,0 @@
|
||||
## 阿里云滑块验证码接入说明(含加密模式)
|
||||
|
||||
|
||||
- 前端需要做什么
|
||||
- 后端需要做什么
|
||||
- 非加密模式 vs 加密模式(`EncryptedSceneId`)
|
||||
- 本项目修改了哪些文件,可以作为参考实现
|
||||
|
||||
下面所有内容以当前项目(`tyc-webview-v2` + `tyc-server-v2`)为例,按步骤说明。
|
||||
|
||||
---
|
||||
|
||||
配置项
|
||||
|
||||
go get github.com/alibabacloud-go/captcha-20230305/client
|
||||
|
||||
Captcha:
|
||||
# 建议与短信相同的 AccessKey,或单独为验证码创建子账号
|
||||
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
||||
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
||||
# 验证码服务 Endpoint,国内一般为 captcha.cn-shanghai.aliyuncs.com
|
||||
EndpointURL: "captcha.cn-shanghai.aliyuncs.com"
|
||||
# 阿里云控制台中该场景的 SceneId,请替换为真实值
|
||||
SceneID: "wynt39to"
|
||||
# 验证码控制台中的 ekey(通常为 Base64 字符串),用于生成 EncryptedSceneId
|
||||
EKey: ""
|
||||
|
||||
index.html
|
||||
<!-- 阿里云滑块验证码 -->
|
||||
<script>
|
||||
window.AliyunCaptchaConfig = { region: "cn", prefix: "12zxnj" };
|
||||
</script>
|
||||
## 一、整体流程概览
|
||||
|
||||
### 1.1 场景说明
|
||||
|
||||
我们使用的是 **阿里云验证码 2.0 / V3 架构** 的滑块验证码,前后端配合流程如下:
|
||||
|
||||
1. 前端在「获取短信验证码」/「查询前无短信码的产品」时,先弹出阿里云滑块验证码。
|
||||
2. 用户拖动成功后,前端拿到 `captchaVerifyParam`,携带到后端业务接口。
|
||||
3. 后端使用阿里云官方 Go SDK(`captcha-20230305`)+ 我们的封装,对 `captchaVerifyParam` 做服务端校验:
|
||||
- 校验通过:继续后续业务逻辑(发短信、查询等)。
|
||||
- 校验失败:直接返回业务错误,例如「图形验证码校验失败」。
|
||||
4. 对于 **加密模式** 场景,前端还需要在初始化时传入 `EncryptedSceneId`,而 `EncryptedSceneId` 由后端用控制台的 `ekey` 生成。
|
||||
|
||||
### 1.2 使用场景(当前项目)
|
||||
|
||||
- 登录页:
|
||||
- **获取短信验证码**:必须先通过滑块验证。
|
||||
- **提交登录**:只校验短信验证码,不再做滑块。
|
||||
- Inquire 查询页:
|
||||
- 有「短信验证码」字段的产品:点击「获取验证码」前滑块;点击「查询」时不需要再次滑块。
|
||||
- 无「短信验证码」的产品:点击「查询」前滑块。
|
||||
|
||||
---
|
||||
|
||||
## 二、前端接入说明(以 Vue 3 / Vite 为例)
|
||||
|
||||
### 2.1 全局基础集成(`index.html`)
|
||||
|
||||
在入口 HTML 中引入阿里云验证码脚本,并预留一个容器:
|
||||
|
||||
- 文件:`tyc-webview-v2/index.html`
|
||||
|
||||
关键片段:
|
||||
|
||||
```html
|
||||
<script>
|
||||
window.AliyunCaptchaConfig = { region: "cn", prefix: "你的前缀" };
|
||||
</script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://o.alicdn.com/captcha-frontend/aliyunCaptcha/AliyunCaptcha.js"
|
||||
></script>
|
||||
...
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="captcha-element"></div>
|
||||
</body>
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- `#captcha-element` 是验证码挂载容器,必须存在。
|
||||
- `AliyunCaptcha.js` 必须在前端业务代码(`/src/main.js`)之前加载。
|
||||
|
||||
### 2.2 通用封装:`useAliyunCaptcha`
|
||||
|
||||
- 文件:`tyc-webview-v2/src/composables/useAliyunCaptcha.js`
|
||||
|
||||
该 composable 封装了:
|
||||
|
||||
- **初始化阿里云验证码实例**(含加密 / 非加密模式);
|
||||
- 提供一个通用方法 `runWithCaptcha(bizVerify, onSuccess)`:
|
||||
- `bizVerify(captchaVerifyParam)`:前端回调,内部调用后端业务接口(发短信、查询等),返回 `{ data, error }`(`useApiFetch` 结果)。
|
||||
- `onSuccess(res)`:当业务 `code === 200` 时调用,`res` 为后端返回的数据。
|
||||
|
||||
使用方式示例:
|
||||
|
||||
```js
|
||||
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
|
||||
|
||||
const { runWithCaptcha } = useAliyunCaptcha();
|
||||
|
||||
function sendLoginSms() {
|
||||
if (!isPhoneValid.value) return;
|
||||
|
||||
runWithCaptcha(
|
||||
(captchaVerifyParam) =>
|
||||
useApiFetch("auth/sendSms")
|
||||
.post({
|
||||
mobile: phoneNumber.value,
|
||||
actionType: "login",
|
||||
captchaVerifyParam,
|
||||
})
|
||||
.json(),
|
||||
(res) => {
|
||||
if (res.code === 200) {
|
||||
// 成功:toast + 开始倒计时 + 聚焦输入框
|
||||
} else {
|
||||
// 失败:toast 提示
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 加密模式开关(前端)
|
||||
|
||||
在 `useAliyunCaptcha.js` 顶部:
|
||||
|
||||
```js
|
||||
// 是否启用加密模式(通过环境变量控制)
|
||||
const ENABLE_ENCRYPTED =
|
||||
import.meta.env.VITE_ALIYUN_CAPTCHA_ENCRYPTED === "true";
|
||||
```
|
||||
|
||||
在 `ensureCaptchaInit()` 中:
|
||||
|
||||
- **非加密模式**(`ENABLE_ENCRYPTED === false`):
|
||||
|
||||
```js
|
||||
if (!ENABLE_ENCRYPTED) {
|
||||
window.initAliyunCaptcha({
|
||||
SceneId: ALIYUN_CAPTCHA_SCENE_ID,
|
||||
mode: "popup",
|
||||
element: "#captcha-element",
|
||||
getInstance(instance) { window.captcha = instance; ... },
|
||||
captchaVerifyCallback(param) { ... },
|
||||
onBizResultCallback(bizResult) { ... },
|
||||
slideStyle: { width: 360, height: 40 },
|
||||
language: "cn",
|
||||
});
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
前端不会请求后端获取 `EncryptedSceneId`,只用 `SceneId` 初始化。
|
||||
|
||||
- **加密模式**(`ENABLE_ENCRYPTED === true`):
|
||||
|
||||
```js
|
||||
const { data, error } = await useApiFetch("/captcha/encryptedSceneId")
|
||||
.post()
|
||||
.json();
|
||||
const resp = data?.value;
|
||||
const encryptedSceneId = resp?.data?.encryptedSceneId;
|
||||
if (error?.value || !encryptedSceneId) {
|
||||
showToast({ message: "获取验证码参数失败,请稍后重试" });
|
||||
// 重置状态
|
||||
captchaInitialised = false;
|
||||
captchaReadyPromise = null;
|
||||
captchaReadyResolve = null;
|
||||
return;
|
||||
}
|
||||
|
||||
window.initAliyunCaptcha({
|
||||
SceneId: ALIYUN_CAPTCHA_SCENE_ID,
|
||||
EncryptedSceneId: encryptedSceneId,
|
||||
mode: "popup",
|
||||
element: "#captcha-element",
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
> 在其它前端平台(React、原生 H5 等),可以复用同样的思路:
|
||||
> - 抽一个 `runWithCaptcha` 工具;
|
||||
> - 初始化逻辑中根据配置决定是否去后端拿 `EncryptedSceneId`,有则带上。
|
||||
|
||||
### 2.4 用户体验:加载提示
|
||||
|
||||
在 `runWithCaptcha` 中增加全局 Loading:
|
||||
|
||||
```js
|
||||
const loading = showLoadingToast({
|
||||
message: "安全验证加载中...",
|
||||
forbidClick: true,
|
||||
duration: 0,
|
||||
loadingType: "spinner",
|
||||
});
|
||||
|
||||
try {
|
||||
// 设置 __captchaVerifyCallback / __onBizResultCallback
|
||||
// await ensureCaptchaInit()
|
||||
// await captchaReadyPromise
|
||||
// window.captcha.show()
|
||||
} finally {
|
||||
closeToast();
|
||||
}
|
||||
```
|
||||
|
||||
这样用户点击按钮后能看到“安全验证加载中”,避免误以为没反应。
|
||||
|
||||
---
|
||||
|
||||
## 三、后端接入说明(Go / go-zero)
|
||||
|
||||
### 3.1 基本配置(`config.go` + `main.yaml`)
|
||||
|
||||
- 文件:`app/main/api/internal/config/config.go`
|
||||
|
||||
```go
|
||||
type CaptchaConfig struct {
|
||||
AccessKeyID string
|
||||
AccessKeySecret string
|
||||
EndpointURL string
|
||||
SceneID string
|
||||
EKey string // 加密模式用的 ekey(Base64)
|
||||
}
|
||||
```
|
||||
|
||||
- 文件:`app/main/api/etc/main.yaml` / `main.dev.yaml`
|
||||
|
||||
```yaml
|
||||
Captcha:
|
||||
AccessKeyID: "你的AccessKeyId"
|
||||
AccessKeySecret: "你的AccessKeySecret"
|
||||
EndpointURL: "captcha.cn-shanghai.aliyuncs.com"
|
||||
SceneID: "控制台场景ID"
|
||||
EKey: "控制台上看到的 ekey(Base64 字符串)"
|
||||
```
|
||||
|
||||
> 其它平台(Java/Spring、.NET 等)也需要同样的配置:
|
||||
> - 一个 Captcha 配置块,包含 AK/SK、Endpoint、SceneId、EKey。
|
||||
|
||||
### 3.2 EncryptedSceneId 生成接口(加密模式)
|
||||
|
||||
#### 3.2.1 生成函数
|
||||
|
||||
- 文件:`pkg/captcha/encrypt_scene.go`
|
||||
|
||||
```go
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
lzcrypto "tyc-server/pkg/lzkit/crypto"
|
||||
)
|
||||
|
||||
// GenerateEncryptedSceneID: sceneId×tamp&expireTime -> AES-256-CBC + PKCS7 -> Base64(IV + ciphertext)
|
||||
func GenerateEncryptedSceneID(sceneId, ekey string, expireSeconds int) (string, error) {
|
||||
if expireSeconds <= 0 || expireSeconds > 86400 {
|
||||
expireSeconds = 3600
|
||||
}
|
||||
|
||||
ts := time.Now().Unix()
|
||||
plaintext := fmt.Sprintf("%s&%d&%d", sceneId, ts, expireSeconds)
|
||||
|
||||
keyBytes, err := base64.StdEncoding.DecodeString(ekey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("decode ekey error: %w", err)
|
||||
}
|
||||
if len(keyBytes) != 32 {
|
||||
return "", fmt.Errorf("invalid ekey length, need 32 bytes after base64 decode, got %d", len(keyBytes))
|
||||
}
|
||||
|
||||
return lzcrypto.AesEncrypt([]byte(plaintext), keyBytes)
|
||||
}
|
||||
```
|
||||
|
||||
> 在其它语言上,只要完全按文档实现同样的算法即可。
|
||||
|
||||
#### 3.2.2 API 声明
|
||||
|
||||
- 文件:`app/main/api/desc/front/user.api`
|
||||
|
||||
```go
|
||||
@server (
|
||||
prefix: api/v1
|
||||
group: captcha
|
||||
)
|
||||
service main {
|
||||
@doc "get encrypted scene id for aliyun captcha"
|
||||
@handler getEncryptedSceneId
|
||||
post /captcha/encryptedSceneId returns (GetEncryptedSceneIdResp)
|
||||
}
|
||||
|
||||
type (
|
||||
GetEncryptedSceneIdResp {
|
||||
EncryptedSceneId string `json:"encryptedSceneId"`
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
#### 3.2.3 逻辑实现
|
||||
|
||||
- 文件:`app/main/api/internal/logic/captcha/getencryptedsceneidlogic.go`
|
||||
|
||||
```go
|
||||
func (l *GetEncryptedSceneIdLogic) GetEncryptedSceneId() (*types.GetEncryptedSceneIdResp, error) {
|
||||
cfg := l.svcCtx.Config.Captcha
|
||||
encrypted, err := captcha.GenerateEncryptedSceneID(cfg.SceneID, cfg.EKey, 3600)
|
||||
if err != nil {
|
||||
l.Errorf("generate encrypted scene id error: %+v", err)
|
||||
return nil, err
|
||||
}
|
||||
return &types.GetEncryptedSceneIdResp{
|
||||
EncryptedSceneId: encrypted,
|
||||
}, nil
|
||||
}
|
||||
```
|
||||
|
||||
> 其它平台只需要提供一个类似的 HTTP 接口即可:
|
||||
> `POST /captcha/encryptedSceneId -> { encryptedSceneId: "xxx" }`
|
||||
|
||||
### 3.3 验证 `captchaVerifyParam`(服务端验签)
|
||||
|
||||
- 文件:`pkg/captcha/aliyun.go`
|
||||
|
||||
使用阿里云官方 Go SDK 验证:
|
||||
|
||||
```go
|
||||
func Verify(cfg Config, captchaVerifyParam string) error {
|
||||
if os.Getenv("ENV") == "development" {
|
||||
return nil
|
||||
}
|
||||
if captchaVerifyParam == "" {
|
||||
return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "empty captchaVerifyParam")
|
||||
}
|
||||
|
||||
clientCfg := &openapi.Config{
|
||||
AccessKeyId: tea.String(cfg.AccessKeyID),
|
||||
AccessKeySecret: tea.String(cfg.AccessKeySecret),
|
||||
}
|
||||
clientCfg.Endpoint = tea.String(cfg.EndpointURL)
|
||||
client, err := captcha20230305.NewClient(clientCfg)
|
||||
...
|
||||
|
||||
req := &captcha20230305.VerifyIntelligentCaptchaRequest{
|
||||
SceneId: tea.String(cfg.SceneID),
|
||||
CaptchaVerifyParam: tea.String(captchaVerifyParam),
|
||||
}
|
||||
resp, err := client.VerifyIntelligentCaptcha(req)
|
||||
...
|
||||
if tea.BoolValue(resp.Body.Result.VerifyResult) {
|
||||
return nil
|
||||
}
|
||||
// 否则返回 "图形验证码校验失败"
|
||||
}
|
||||
```
|
||||
|
||||
在需要滑块的业务逻辑里(发送短信、查询),调用:
|
||||
|
||||
```go
|
||||
cfg := l.svcCtx.Config.Captcha
|
||||
if err := captcha.Verify(captcha.Config{
|
||||
AccessKeyID: cfg.AccessKeyID,
|
||||
AccessKeySecret: cfg.AccessKeySecret,
|
||||
EndpointURL: cfg.EndpointURL,
|
||||
SceneID: cfg.SceneID,
|
||||
}, req.CaptchaVerifyParam); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
```
|
||||
|
||||
> 其它语言平台(Java、Node.js 等)可以用对应的阿里云 SDK 实现相同的服务端校验。
|
||||
|
||||
### 3.4 sendSms 接口示例
|
||||
|
||||
- 文件:`app/main/api/internal/logic/auth/sendsmslogic.go`
|
||||
|
||||
```go
|
||||
func (l *SendSmsLogic) SendSms(req *types.SendSmsReq) error {
|
||||
// 1. 图形验证码校验
|
||||
cfg := l.svcCtx.Config.Captcha
|
||||
if err := captcha.Verify(captcha.Config{...}, req.CaptchaVerifyParam); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 原来的手机号加密、频率限制、阿里短信发送、Redis 存验证码等逻辑
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、关键文件清单
|
||||
|
||||
- 前端:
|
||||
- `tyc-webview-v2/index.html`:引入 `AliyunCaptcha.js`、提供 `#captcha-element`。
|
||||
- `tyc-webview-v2/src/composables/useAliyunCaptcha.js`:通用封装,支持加密/非加密模式 + Loading 提示。
|
||||
- `tyc-webview-v2/src/views/Login.vue`:获取短信前通过 `runWithCaptcha` 调用 `/auth/sendSms`。
|
||||
- `tyc-webview-v2/src/components/InquireForm.vue`:查询前根据是否有短信验证码字段决定是否通过 `runWithCaptcha`。
|
||||
|
||||
- 后端:
|
||||
- `app/main/api/internal/config/config.go`:`CaptchaConfig` 增加 `EKey`。
|
||||
- `app/main/api/etc/main.yaml` / `main.dev.yaml`:补充 `Captcha` 配置(SceneID + EKey)。
|
||||
- `app/main/api/desc/front/user.api`:声明 `/captcha/encryptedSceneId` 接口。
|
||||
- `app/main/api/internal/logic/captcha/getencryptedsceneidlogic.go`:生成 `EncryptedSceneId`。
|
||||
- `pkg/captcha/encrypt_scene.go`:`GenerateEncryptedSceneID` 实现。
|
||||
- `pkg/captcha/aliyun.go`:`Verify` 实现(调用阿里云 SDK)。
|
||||
- `app/main/api/internal/logic/auth/sendsmslogic.go`:发送短信前调用 `captcha.Verify`。
|
||||
- `app/main/api/internal/logic/query/queryservicelogic.go`:对无短信验证码的产品,在查询前调用 `captcha.Verify`。
|
||||
|
||||
---
|
||||
|
||||
## 五、接入其它平台时的注意事项
|
||||
|
||||
1. **SceneId / ekey 必须一一对应**
|
||||
- 控制台“场景管理”里的 SceneId 和 ekey 必须和配置里完全一致。
|
||||
- 多个场景要分别管理 SceneId / ekey。
|
||||
|
||||
2. **时间同步**
|
||||
- 加密模式依赖 `timestamp` 和 `expireTime`,服务器时间要尽量准确(建议 NTP 同步)。
|
||||
|
||||
3. **前后端模式一致**
|
||||
- 如果控制台开启了加密模式,前端必须**带上 `EncryptedSceneId`**;
|
||||
- 如果前端只传 `SceneId`,在加密模式下会被阿里云直接拒绝(出现类似 F022 错误码)。
|
||||
|
||||
4. **错误处理**
|
||||
- 服务端 `Verify` 出错(网络、阿里云故障)时,我们当前策略是**记录日志但视为通过**,防止影响业务可用性——这一点可根据各平台风险偏好调整。
|
||||
|
||||
5. **复用策略**
|
||||
- 不同前端技术栈(Vue/React/小程序等),只要能做到:
|
||||
1. 初始化时根据配置决定是否从后端拿 `EncryptedSceneId`;
|
||||
2. 在业务请求前通过验证码拿到 `captchaVerifyParam` 并传给后端;
|
||||
- 后端则统一在与风控相关的接口上调用相同的 `Verify` 封装即可。
|
||||
|
||||
---
|
||||
|
||||
## 六、推荐的接入步骤
|
||||
|
||||
1. 在阿里云验证码控制台创建场景,记下 **SceneId** 和 **ekey**,并根据需要打开「加密模式」。
|
||||
2. 在你自己的后端项目里:
|
||||
- 增加 Captcha 配置块(AccessKeyID、AccessKeySecret、EndpointURL、SceneID、EKey);
|
||||
- 实现 EncryptedSceneId 生成接口 `/captcha/encryptedSceneId`(可参考本项目的 `GenerateEncryptedSceneID`);
|
||||
- 在需要滑块的业务接口(发短信、查询)前调用阿里云 SDK 做 `captchaVerifyParam` 校验。
|
||||
3. 在你自己的前端项目里:
|
||||
- 页面引入 `AliyunCaptcha.js` 并预留验证码容器;
|
||||
- 抽一个类似 `runWithCaptcha(bizVerify, onSuccess)` 的封装;
|
||||
- 业务按钮点击时,不直接调接口,而是先触发 `runWithCaptcha`:
|
||||
- 前端拉取 `EncryptedSceneId`(若启用加密模式);
|
||||
- 初始化 `initAliyunCaptcha` 并弹出滑块;
|
||||
- 滑块通过后才真正调用后端业务接口。
|
||||
Reference in New Issue
Block a user