搜索引擎优化(SEO)
原理
i18n.site
采用了无刷新单页面架构,为了方便搜索索引,会生成单独静态页面和sitemap.xml
让爬虫抓取。
当访问请求的User-Agent
被为搜索引擎的爬虫时,会通过302
将请求重定向到静态页面。
静态页面上,用link
标明此页面不同语言版本的链接,比如:
<link rel=alternate hreflang=zh href="https://i18n.site/zh/.htm">
<link rel=alternate hreflang=en href="https://i18n.site/en/.htm">
本地 nginx 配置
以演示项目中.i18n/htm/main.yml
配置文件为例
host: i18n-demo.github.io
seo: true
out:
- fs
pkg:
i: i18n.site
md: i18n.site
cdn:
v:
jsd:
请首先修改上面host:
的值为您的域名,比如xxx.com
。
然后,i18n.site -n
,静态页面会生成到 out/main/htm
目录下。
当然你也可以启用其他配置文件,比如先参考main
的配置创建.i18n/htm/dist.package.json
和.i18n/htm/dist.yml
。
然后运行i18n.site -n -c dist
,这样静态页面会生成到out/dist/htm
。
nginx
可以参考下面的配置来设置
map $http_user_agent $botLang {
"~*baidu|yisou|sogou|360|byte" "/zh";
"~*facebookexternalhit|slurp|bot|spider|curl" "/en";
default "";
}
server {
http2 on;
listen 443 quic ;
listen 443 ssl ;
listen [::]:443 quic ;
listen [::]:443 ssl ;
add_header Alt-Svc 'h3=":443";ma=99999;persist=1';
server_name doc.flashduty.com;
ssl_certificate /root/.acme.sh/doc.flashduty.com_ecc/fullchain.cer;
ssl_certificate_key /root/.acme.sh/doc.flashduty.com_ecc/doc.flashduty.com.key;
root /mnt/doc.flashduty.com;
# server worker 的脚本不要缓存太久
location = /S.js {
add_header Cache-Control "max-age=600";
}
# 其他静态资源设置较长的缓存时间
location ~* \.(js|css|htm|html|md|avif|json|ico|xml|rss|gz|mp4|png|svg|txt|webmanifest)$ {
add_header Cache-Control "max-age=999999";
}
# 设置爬虫用哪个静态文件作为首页入口
location = / {
# 如果 $botLang 不为空,则表示是爬虫访问,根据设置的语言路径重定向
if ($botLang) {
return 301 $botLang/flashduty.htm;
}
add_header Cache-Control "max-age=600";
rewrite ^ /index.html break;
}
# 单页面应用配置
location / {
if ($botLang) {
return 302 $botLang$request_uri.htm;
}
add_header Cache-Control "max-age=600";
rewrite ^ /index.html break;
}
}
server {
server_name doc.flashduty.com;
listen 80;
listen [::]:80 ;
location / {
rewrite ^(.+) https://$host$1 permanent;
}
location /.well-known/acme-challenge/ {
root /mnt/doc.flashduty.com/;
}
}
配置上传静态文件的对象存储
静态文件可以生成到本地,但更常见的做法是将其上传到对象存储。
修改上面配置的out
为:
out:
- s3
然后,编辑~/.config/i18n.site.yml
,加入如下的配置:
site:
i18n.site:
s3:
- endpoint: s3.eu-central-003.backblazeb2.com
ak: # access key
sk: # secret key
bucket: # bucket name
# region:
配置中,i18n.site
请修改为.i18n/htm/main.yml
中host:
的值,s3
下面可以配置多个对象存储,region
字段是可选的(很多对象存储不需要设置此字段)。
然后运行i18n.site -n
重新发布项目。
如果修改了~/.config/i18n.site.yml
, 想重新上传, 请在项目根目录下, 用下面的命令清理上传缓存:
rm -rf .i18n/data/seo .i18n/data/public
cloudflare 配置
域名托管到 cloudflare 。
转换规则
添加如下图的转换规则:
规则代码如下,请修改代码"i18n.site"为你的域名:
(http.host in {"i18n.site"}) and not (
substring(http.request.uri.path,-3) in {".js" ".gz"} or
substring(http.request.uri.path,-4) in {".htm" ".rss" ".css" ".svg" ".ico" ".png" ".xml" ".txt"} or
substring(http.request.uri.path,-5) in {".html" ".avif" ".json"} or
ends_with(http.request.uri.path,".webmanifest")
)
缓存规则
添加缓存规则如下:
(substring(http.request.uri.path,-4) in {".htm" ".rss"}) or ends_with(http.request.uri.path,"/sitemap.xml") or ends_with(http.request.uri.path,".xml.gz")
重定向规则
设置重定向规则如下,请修改代码"i18n.site"为你的域名
(http.host in {"i18n.site"}) and not (
substring(http.request.uri.path,-3) in {".js" ".gz"} or
substring(http.request.uri.path,-4) in {".htm" ".rss" ".css" ".svg" ".ico" ".png" ".xml" ".txt"} or
substring(http.request.uri.path,-5) in {".html" ".avif" ".json"} or
ends_with(http.request.uri.path,".webmanifest")
) and (
http.user_agent wildcard "*bot*" or
http.user_agent wildcard "*spider*" or
http.user_agent wildcard "*facebookexternalhit*" or
http.user_agent wildcard "*slurp*" or
http.user_agent wildcard "curl*" or
http.user_agent wildcard "*InspectionTool*"
)
URL redirect
选择动态重定向,请修改重定向路径concat("/en",http.request.uri.path,".htm")
中的/en
为你想让搜索引擎收录默认语言。
百度智能云配置
如果你需要面向中国大陆地区提供服务,可以使用百度智能云。
数据上传到百度对象存储,并绑定到百度内容分发网络。
然后在 EdgeJS边缘服务 创建脚本如下
const uri = r.uri, p = uri.lastIndexOf(".");
if (
p < 0 ||
!"|js|css|htm|html|md|avif|json|ico|xml|rss|gz|mp4|png|svg|txt|webmanifest|".includes(
"|" + uri.slice(p + 1) + "|",
)
) {
const ua = r.headersIn["User-Agent"].toLowerCase()
if (/facebookexternalhit|slurp|bot|spider|curl/.test(ua)) {
r.return(
302,
(/baidu|yisou|sogou|360|byte/.test(ua) ? "/zh" : "/en") + r.uri + ".htm",
)
} else {
r.uri = "/index.html"
}
}
r.respHeader(() => {
const t = [], out = r.headersOut;
["Content-MD5", "Age", "Expires", "Last-Modified"].forEach(
i => delete out[i]
)
r.rawHeadersOut.forEach(i => {
const key = i[0].toLowerCase()
if (key.startsWith("x-") || key.startsWith("ohc-")) {
delete out[key]
}
})
out["Cache-Control"] = "max-age=" + 9e5
// 可设置响应头来调试输出,比如 out.XXX = 'MSG';
})
点击Debug
,然后点击全网发布。
高级用法: 基于地域解析分发流量
如果你既想在中国大陆地区提供服务,又想要cloudflare
的免费国际流量,可以使用带有地域解析的DNS
。
比如华为云DNS就提供了免费的地域解析,借助它可以实现中国大陆流量走百度智能云,国际流量走cloudflare
。
cloudflare
的配置有不少坑,这里说几个注意点:
域名托管在其他DNS
,怎么用cloudflare
首先绑定一个任意域名到cloudflare
,然后借助SSL/TLS
→ 自定义域名,关联主域名到此域名。
cloudflare R2
无法通过自定义域名访问
因为cloudflare
自带的对象存储R2
无法自定义域名访问,所以需要用第三方的对象存储来放置静态文件。
这里以 backblaze.com 为例,演示怎么绑定第三方对象存储到cloudflare
。
在backblaze.com
创建存储桶,上传任意文件,点击浏览文件,获取Friendly URL
的域名,这里是f003.backblazeb2.com
。
在cloudflare
将域名CNAME
到f003.backblazeb2.com
,并开启代理。
修改cloudflare
的SSL
→ 加密模式,设置为Full
添加转换规则如下图,放在首位(首位优先级最低):
Rewrite to
选择动态,修改concat("/file/your_bucketname",http.request.uri.path)
中的your_bucketname
为你的存储桶名。
此外,上文的cloudflare
转换规则 中index.html
改为file/your_bucketname/index.html
,其他配置照旧。