前言
前段时间我们的官网上了新版本, 有将一些对 seo 不友好的旧页面的路由变成了新页面的路由。 比如将 bizHome.html
换成 business/
, 但是其实内容是一样的。
刚开始为了保证旧页面不失效,在构建的时候,是将新页面和旧页面的内容都构建成一样的。 但是这样子一来, seo 的权重就被割裂了。
所以为了保证新页面的 seo 权重能够继承旧页面的权重。就要换成将旧页面的访问全部变成 301 的永久跳转到新页面上。
nginx 进行 301 跳转
如果要进行 301 永久性跳转的话,是没办法在前端层面上进行的。 只能在服务端上进行, 而我们用的是 webserver 是 nginx, 所以要在 nginx 上面配置。
旧网址 | 301跳转到新网址 |
---|---|
https://www.foo.com/get.html |
https://www.foo.com/download/foo-personal/ |
https://www.foo.com/get.html?init=business |
https://www.foo.com/download/foo-business/ |
https://www.foo.com/pricing/?init=biz |
https://www.foo.com/pricing/foo-business/ |
https://www.foo.com/pricing/?init=personal |
https://www.foo.com/pricing/foo-personal/ |
https://www.foo.com/pricing/ |
https://www.foo.com/pricing/foo-personal/ |
所有 pt-pt 的网址都要 301 跳转到 pt-br | - |
而且我们的页面都是有小语种,也就是重定向之后,小语种的路由要在,比如 /en/get.html
301 跳转之后就是 /en/download/foo-personal
使用 rewrite 来进行重定向
nginx 设置 301 重定向有好几种, 直接 return 301 url
最简单。 不过因为我们这边会涉及到多语言路径也要带过去, 所以会有正则表达式匹配的需求,所以就用 rewrite 来处理。
rewrite 语法:1
rewrite regex replacement[flag];
rewrite 是实现 URL 重定向的重要指令,他根据regex(正则表达式)来匹配内容跳转到 replacement,结尾是 flag 标记
他可以应用的位置是 server
, location
, if
这几个内容块里面。
他的应用 regex 的参数其实是 nginx 的内置变量 $uri
, 也就是 url 的 path, 不包含传递的参数和锚点。
比如 https://www.foo.com/a/b/index.html?name=1&age=2#hello
这个 url,那么应用 regex 的 url 就是 /a/b/index.html
举个例子,像我们之前做多语言的时候,如果这个多语言路径不存在的话,那么就会重定向到非多语言的路径去。1
2
3if (!-e $request_filename) {
rewrite ^/([A-Za-z0-9_-]+)/(.*) /$2 permanent;
}
这边就会用到这个 rewrite 语法, 具体的表现就是,如果我请求 https://www.foo.com/ru/download/
这个页面的时候,如果这个页面不存在, 那么就会 301 重定向到 https://www.foo.com/download/
而且最后的这个 flag
的值 permanent
表示跳转行为为 301 的永久重定向。 flog
有以下值:
last
: 本条规则匹配完成后继续向下匹配新的location URI规则break
: 本条规则匹配完成后终止,不在匹配任何规则redirect
: 返回302临时重定向permanent
: 返回301永久重定向
具体实操
针对上面的这几个旧页面, 处理一下 301 重定向。 因为这边涉及到 location 规则的匹配,具体可以看: Nginx 的 location 匹配规则总结
1. 首先是针对 get.html 的处理
处理逻辑如下:1
2
3
4
5
6if ($request_uri ~* "get.html\\?init=business") {
rewrite ^/(.*)get.html$ /$1download/foo-business/ permanent;
}
if ($request_uri ~* "get.html") {
rewrite ^/(.*)get.html$ /$1download/foo-personal/ permanent;
}
这边注意一个细节, 重定向的逻辑 都在 if 判断的块里面, 是因为只有这些特殊的页面才需要重定向。 而判断的 $request_uri
也是 nginx 的内置变量, 不过这个跟 $uri
变量不一样,他还包含后面的请求参数, 只不过他是不能被修改的。
然后会在 rewrite 的正则里面将 多语言的路径提取出来,并放到新的路径里面。
而且替换后的也是 uri 部分, 后面的参数还是会跟原来的。也就是会将 /en/get.html?name=1
变成 /en/download/foo-personal/?name=1
2. 对 pricing 界面的处理
1 | if ($request_uri ~* "/pricing(/)?(index.html)?\\?init=biz") { |
逻辑跟上面差不多,不过需要注意一点的是,因为这个页面,有时候会省略 index.html
, 有时候甚至连 /
都省略。 所以还要兼容以上两种情况, 所以用了两个 ?
来做兼容。
3. 对 pt-pt 做处理
这个就很简单了,直接瞄准 pt-pt
的语言路径:1
2
3if ($request_uri ~* "/pt-pt/") {
rewrite ^/(pt-pt)(.*) /pt-br$2 permanent;
}
然后替换成固定的 pt-br
即可。
最后替换完之后,要做两步:
- 执行
nginx -t
进行语法检查 - 执行
nginx -s reload
重启 nginx, 让配置文件生效
测试
测试的话,很简单,用 curl 测试就行了。 使用参数 -I
, 然后直接看 location 头部就行了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48[root@VM-156-200-centos ~]# curl -I https://www.foo.com/get.html
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/download/foo-personal/
...
[root@VM-156-200-centos ~]# curl -I https://www.foo.com/zh-cn/get.html
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/zh-cn/download/foo-personal/
...
[root@VM-156-200-centos ~]# curl -I https://www.foo.com/zh-cn/get.html?name=1
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/zh-cn/download/foo-personal/?name=1
...
[root@VM-156-200-centos ~]# curl -I https://www.foo.com/zh-cn/get.html?init=business
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/zh-cn/download/foo-business/?init=business
...
[root@VM-156-200-centos ~]# curl -I https://www.foo.com/pt-pt/
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/pt-br/
...
[root@VM-156-200-centos ~]# curl -I https://www.foo.com/pricing/
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/pricing/foo-personal/
...
[root@VM-156-200-centos ~]# curl -I https://www.foo.com/zh-cn/pricing
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/zh-cn/pricing/foo-personal/
...
[root@VM-156-200-centos ~]# curl -I https://www.foo.com/zh-cn/pricing/index.html?init=biz
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/zh-cn/pricing/foo-business/?init=biz
...
不过这边要注意一个细节,在使用 curl 的时候,如果参数后面有 &
要转义,不然会报错, 导致参数传递不全 (直接输入浏览器之所以不用,是因为浏览器帮我们自动转义了)1
2
3
4
5[root@VM-156-200-centos ~]# curl -I https://www.foo.com/zh-cn/get.html?name=1&age=2
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/zh-cn/download/foo-personal/?name=1
...
就会发现 &
后面的参数丢了。
这个是因为在使用 curl
的时候,参数的连接符 &
是要进行转义的, 所以加上转义符号就可以 (当然也可以不用转义, 直接将 url 用双引号括起来就行了):1
2
3
4
5[root@VM-156-200-centos ~]# curl -I https://www.foo.com/zh-cn/get.html?name=1\&age=2
HTTP/1.1 301 Moved Permanently
...
Location: https://www.foo.com/zh-cn/download/foo-personal/?name=1&age=2
...
如果 nginx 针对某个路由设置 301 跳转,并且排除某一个符合条件的路由,单单上面那种操作是不够的, 具体看: nginx 针对某个路由设置 301 跳转,并且排除某一个符合条件的路由