无需改动代码让SPA项目支持SEO

无需改动代码让SPA项目支持SEO

随着前端技术的发展,页面路由逐渐移到了前端,页面由客户端浏览器进行渲染。项目创立之初可能没考虑到 SEO,后期需要对项目做侵入式修改,这个开源项目,正是为了解决这一问题而诞生的。

简介

Architecture
rendora 是基于 Go 开发的一个类似代理服务器一样的 SSR 解决方案,可以在无需修改现有项目代码的情况下,实现对 Vue、React、Angular 等 SPA 项目的服务端渲染。

主要功能:

  • 配置简单
  • 无需修改原有项目
  • 支持 Redis 缓存
  • 提供 REST ful API
  • 支持 Prometheus 监控
  • 支持任意路由页面的渲染
  • 不受限于前端框架与所使用到的技术
  • 不渲染无效资源(如图片、字体和 CSS),以加快 DOM 渲染
  • 搜索引擎爬虫和普通用户获取到的数据一致(得益于 Chrome API)

其实 rendora 在架构中的位置是可以自行定义的,它既可以放在最前端,也可以放在 Nginx 的后面,等于是在 Nginx 层做决策,来判断请求是来自用户还是爬虫。

开始部署

运行无头浏览器

1
2
3
4
5
# 可以在 Docker 上运行
$ docker run --tmpfs /tmp --net=host rendora/chrome-headless

# Mac 上如果安装了 Google Chrome 浏览器,可以使用如下方式运行
$ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --headless --remote-debugging-port=9222

必要配置

1
2
3
4
target: # 无头浏览器请求的地址
url: "http://10.0.8.100:8080"
backend: # 原 SPA 页面的主机地址
url: "https://spa.example.it"

注意: target.url 是当请求被允许通过 Chrome headless 渲染时,所转发的地址,backend.url 用来定义当请求未被允许通过 Chrome headless 渲染时,将请求转发到该地址。

配置说明

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
listen: #设置 Rendora 服务的绑定地址和监听端口 (可选)
address: 0.0.0.0 # 默认 0.0.0.0
port: 3001 # 默认 3001
cache: #设置用于缓存的驱动(可选)
type: redis # 支持 local 和 redis 两种缓存模式,默认是 local
timeout: 6000 # 缓存生命周期,单位:秒
redis:
address: localhost:6379
password: PASSWORD # Redis 密码
db: 0 # 默认使用 0
keyPrefix: Key 前缀 # 默认值为 __:::rendora:
target: # 无头浏览器请求的 SPA 地址,当判断为需要 SSR 渲染时会将请求转发到该地址
url: "http://10.0.8.100:8080"
backend: # 原 SPA 页面的主机地址
url: "https://spa.example.it"
headless: # 无头浏览器配置
waitAfterDOMLoad: 0 # 在初始DOM加载事件后等待的超时时间(以毫秒为单位),默认值为 0
timeout: 15 # 用于指定 Rendora 等待无头浏览器响应的超时时间,如果在该时间内未获得无头浏览器的响应,则会向客户端返回 500 状态码,默认值 15
internal:
url: http://localhost:9222 # 指定无头浏览器的地址,默认为 http://localhost:9222
blockedURLs: # 定义无需加载的资源,可以使用通配符或者绝对 URL
- "*.png"
- "*.jpg"
- "*.jpeg"
- "*.webp"
- "*.gif"
- "*.css"
- "*.woff2"
- "*.svg"
- "*.woff"
- "*.ttf"
- "https://www.youtube.com/*"
- "https://www.google-analytics.com/*"
- "https://fonts.googleapis.com/*"
output:
minify: true # 是否压缩 HTML
filters: # 定义过滤器
userAgent:
defaultPolicy: blacklist # 定义默认策略 whitelist 和 blacklist,默认值为 blacklist
exceptions: # 用于定义例外,如果 defaultPolicy 为 whitelist,则这里定义的将会是 blacklist
keywords:
- bot
- slurp
- bing
- yandex
- crawler
exact: # 可以过滤指定的浏览器
- Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
paths: # 仅在检查请求用户代理并通过其过滤器后才检查路径
defaultPolicy: whitelist
exceptions:
prefix:
- /users/
exact:
- /api/
debug: false # 是否开启 Debug 模式
server: # Rendora API 的配置
enable: false
listen:
address: 0.0.0.0
port: 9242
auth:
enable: false
name: X-Auth-Rendora # HTTP身份验证标头名称
value: '' #定义用于身份验证的 token

安装

Docker

1
$ docker run --net=host -v ./CONFIG_FILE.yaml:/etc/rendora/config.yaml rendora/rendora

注意:目前通过 Docker 搭建的 Rendora 服务无法连接,在 Github 上已经有人提了 Issue

源码

1
2
3
4
5
$ git clone https://github.com/rendora/rendora
$ cd rendora
$ make build
$ sudo make install
$ rendora --config CONFIG_FILE.yaml

场景分析

Rendora 作为最前端的反向代理

对于很多人来说,因为没有形成概念,理解 target 和 backend 的区别有点困难,我当初也是非常困惑,通过多次测试明白了两个设置的作用。下面模拟一个场景,通过场景来解释配置的作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
target: # 无头浏览器请求的地址
url: "http://10.0.8.100:8000"
backend: # 原 SPA 页面的主机地址
url: "https://spa.example.it"
headless:
waitAfterDOMLoad: 10
timeout: 5
internal:
url: "http://localhost:9222"
output:
minify: true
filters:
userAgent:
defaultPolicy: blacklist
exceptions:
keywords:
- bot
- slurp
- bing
- crawler
debug: true

例如上面的配置中,target.url 指向的是内部的 SPA 项目地址,也就是上图中的 SPA 模块,backend.url 指向的就是通过 Nginx 访问的。

思考

通过架构图可以发现,其实原理非常简单,就是通过一层类似中间件的服务,让他来调用 Chrome 的 API,让 Chrome 渲染页面然后返回给爬虫。那么我们也可以通过 Nginx 来搭配 Lua 来实现同样的功能。

评论