0x01 前言

我建站都适用Wordpress ,而无论是Wordpress 本体还是模版甚至是插件或多或少都有使用Google 的fonts 库与ajax 库。其实Wordpress 正常情况下是很快的、效率是很高的,因为使用了Google 某些服务的原因而导致某些资源不断处于加载状态。

如果你的网站并没有使用HTTPS协议,也可以选择免费的360的前端公共库服务。如果你启用了HTTPS协议,又不想自己配置反向代理,请选用由中国科学技术大学ustclug 提供的服务。地址如下:

还有一种选择就是像我一样,在有足够资源的情况下自行配置反向代理。

0x02 链接结构

0x02.1 fonts.googleapis.com

首先来看看Google 的字体库,以下是这次用来做分析的链接:

https://fonts.c4.hk/css?family=Open+Sans

#前面是固定的链接结构
https://fonts.c4.hk/css?family=

#"family=" 后跟随的就是请求的字体,这里请求Open Sans Normal 400 这个字体
Open+Sans

如果你需要别的字体,可以到以下地址去自行配置并获取相应的引用地址:

0x02.2 fonts.googleapis.com 返还内容

/* cyrillic-ext */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'), local('OpenSans'), url(https://fonts.c4.hk/s/opensans/v13/K88pR3goAWT7BTt32Z01m4X0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
  unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
/* cyrillic */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'), local('OpenSans'), url(https://fonts.c4.hk/s/opensans/v13/RjgO7rYTmqiVp7vzi-Q5UYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'), local('OpenSans'), url(https://fonts.c4.hk/s/opensans/v13/LWCjsQkB6EMdfHrEVqA1KYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'), local('OpenSans'), url(https://fonts.c4.hk/s/opensans/v13/xozscpT2726on7jbcb_pAoX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
  unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'), local('OpenSans'), url(https://fonts.c4.hk/s/opensans/v13/59ZRklaO5bWGqF5A9baEEYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
  unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'), local('OpenSans'), url(https://fonts.c4.hk/s/opensans/v13/u-WUoqrET9fUeobQW7jkRYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'), local('OpenSans'), url(https://fonts.c4.hk/s/opensans/v13/cJZKeOuBrn4kERxqtaUH3ZBw1xU1rKptJj_0jans920.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}

注意里面的url 引用地址:fonts.gstatic.com ,正是这个地址,在某些地区被禁止访问,我们需要对其进行替换。

这样一来,我们需要用一个域名对两个Google 地址进行反向代理,有点复杂,但不难。

0x02.3 ajax.googleapis.com

ajax 的情况比fonts 要好,直接通过代理就好了,并不需要过多分析:

ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js?ver=3.4.2

0x03 反向代理 fonts.googleapis.com

因为我所配置的所有的网站都使用HTTPS 协议,所以配置文件中包含有nginx SSL 部分。但这里并不对nginx SSL 展开分析说明,请注意。

0x03.1 逻辑

  1. 用户浏览访问https://fonts.odin.org.cn/css?family=Open+Sans ;
  2. nginx 检测到/css 这个路径适配其中一个location ,将请求转发到fonts.googleapis.com;
  3. nginx 接收fonts.googleapis.com 返还的内容,并将其中的https://fonts.c4.hk 替换为 //fonts.odin.org.cn ,并将内容重新打包转发给用户;
  4. 用户接收到修改过的内容并按需获取字体文件,但地址访问的地址是修改过的fonts.odin.org.cn;
  5. nginx 再次接受到用户的请求并检测到路径/ 适配其中一个location ,所以将这个请求转发到https://fonts.c4.hk;
  6. nginx 接收到fonts.gstatic.com 返还的内容,原封不动地转发给用户。

0x03.2 配置server 块

server {
	#监听https 端口
    listen                  443 ssl http2;

    #监听http 端口
    listen                  80;

    #绑定域名
    server_name             fonts.odin.org.cn;

    #启用SSL 模块
    ssl                     on;

    #SSL 数字证书位置
    ssl_certificate         /your ssl crt. path/odin.org.cn.crt;

    #SSL 数字证书密钥路径
    ssl_certificate_key     /usr/local/nginx/ssl/odin.org.cn.key;

    #SSL 缓存
    ssl_buffer_size         16k;

    #SSL 算法
    ssl_ciphers             ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:DES-CBC3-SHA;

    #
    ssl_prefer_server_ciphers   on;

    #SSL 协议
    ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;

    #
    ssl_session_cache       builtin:20480 shared:SSL:10m;

    #
    ssl_session_timeout     10m;

    #
    ssl_stapling            on;

    #
    ssl_session_tickets     on;
}

0x03.3 反向代理 fonts.googleapis.com

需要先获取fonts.googleapis.com 返还的内容,才能对其中的内容作出修改,所以先配置反向代理fonts.googleapis.com 的location 块。

因为要通过一个私有地址代理两个Google 地址,所以要通过链接结构进行区分,而所有字体都在(fonts.googleapis.com/css )css 目录下,所以对css 目录下的文件进行反向代理:

	#设定路径
	location /css {

		#设定Host 头部,告知源服务器要访问那个域名的资源
		proxy_set_header Host fonts.googleapis.com;

		#将css 目录下的所有请求转发到https:\/\/fonts.googleapis.com
		#请忽略转义符,因为我配置文件的原因,要在正文内加入转义符才能正常显示某些地址
		proxy_pass https:\/\/fonts.googleapis.com;

		#保留源站的响应头
		proxy_pass_header Server;

		#因为要替换返还的内容,通过Accept-Encoding 防止源站返回压缩过的内容。压缩过的内容不能被替换!
		proxy_set_header Accept-Encoding '';

		#将用户的真实IP 包含在请求内容中
		proxy_set_header X-Real-IP $remote_addr;

		#将请求协议包含在请求内容中,其实这行可以去掉
		proxy_set_header X-Scheme $scheme;

		#禁止跳转
		proxy_redirect off;

		#默认sub_filter_once 是处于on ,关闭它以便一次替换多行
		sub_filter_once off;

		#允许替换内容的文件类型,其实这里只有text/css 这一种类型,但我为了方便而实用通配符*
		sub_filter_types *;

		#将返还回来的内容里匹配https://fonts.c4.hk 的字符替换为 //fonts.odin.org.cn 
		#因为我要适配http 的使用情况,而不得不设置为 //fonts.odin.org.cn 。
		#如果你确定只用于http 或 https ,也可以加上协议:http://fonts.odin.org.cn 或 https//fonts.odin.org.cn
		sub_filter 'https://fonts.c4.hk' '//fonts.odin.org.cn';
	}

注意:请将上面代码中的地址fonts.odin.org.cn 替换为你自己的地址!

0x03.4 反向代理fonts.gstatic.com

	#设定路径
	location / {

		#设定Host 头部,告知源服务器要访问那个域名的资源
		proxy_set_header Host fonts.gstatic.com;

		#将/ 目录下的所有请求转发到https://fonts.c4.hk
		proxy_pass https://fonts.c4.hk;

		#保留源站的响应头
		proxy_pass_header Server;

		#将用户的真实IP 包含在请求内容中
		proxy_set_header X-Real-IP $remote_addr;

		#将请求协议包含在请求内容中,其实这行可以去掉
		proxy_set_header X-Scheme $scheme;

		#禁止跳转
		proxy_redirect off;
}

0x04 反向代理ajax.googleapis.com

通过同样的方法对ajax.googleapis.com 进行反向代理:

server {
    listen                  443 ssl http2;
    listen                  80;
    server_name             ajax.odin.org.cn;

    ssl                     on;
    ssl_certificate         /your ssl crt. path/odin.org.cn.crt;
    ssl_certificate_key     /usr/local/nginx/ssl/odin.org.cn.key;
    ssl_buffer_size         16k;
    ssl_ciphers             ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:DES-CBC3-SHA;
    ssl_prefer_server_ciphers   on;
    ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache       builtin:20480 shared:SSL:10m;
    ssl_session_timeout     10m;
    ssl_stapling            on;
    ssl_session_tickets     on;

	location / {
		proxy_set_header Host ajax.googleapis.com;

		#请忽略转义符,因为我配置文件的原因,要在正文内加入转义符才能正常显示某些地址
		proxy_pass https:\/\/ajax.googleapis.com;
		proxy_pass_header Server;

		proxy_set_header Accept-Encoding '';
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Scheme $scheme;

		proxy_redirect off;

		sub_filter_once off;
		sub_filter_types *;
		sub_filter 'fonts.googleapis.com' 'fonts.odin.org.cn';
		sub_filter 'fonts.gstatic.com' 'fonts.odin.org.cn';
		sub_filter 'ajax.googleapis.com' 'ajax.odin.org.cn';

	}
}

0x05 缓存

因为以上内容都是静态内容,并不会因为请求时间或地点的不同而不同,每个链接都对应唯一的响应内容,所以缓存是极其重要的。缓存可以减少对Google 服务器访问的次数,从而减少响应时间。

首先要在nginx.conf 的http 块中添加以下内容:

    #proxy_cache_path 缓存文件存放路径,请根据需要自行设置并自行建立文件夹
    #levels 定义文件夹的级数,例如:
    /*
	proxy_cache_path /var/tmp/nginx/proxy_cache levels=1:2 keys_zone=one:10m;
	#路径和文件名像这样:
	/var/tmp/nginx/proxy_cache/c/29/b7f54b2df7773722d382f4809d65029c
	*/
	#keys_zone 定义缓存区域名称与大小
	#inactive 缓存有效期,当文件在设定的时间内没有被访问将被删除
	#最大容量,如果超出,将删除使用率最低的文件
    proxy_cache_path                    /var/tmp/nginx/proxy_cache levels=1:2 keys_zone=content:10g inactive=30d max_size=15g;

    #为每一个缓存文件建立唯一的key
    proxy_cache_key                     $host$proxy_host$uri$is_args$args;

然后在每个location 添加以下内容:

#定义要使用的缓存区域
proxy_cache content;

#给对应的状态码设置缓存有效期,这里的状态码是指源站返回的状态码
proxy_cache_valid  200 304 301 302 30d;
proxy_cache_valid  any 30s;

0x06 结语

我将我自己反向代理fonts.gstatic.com 、ajax.googleapis.com 和gravatar.com 的配置文件放在Github ,有需要的朋友请到以下链接查看:

0x07 相关视频

https://www.bilibili.com/video/av11438151/