Serenader

Learning by sharing.

使用 Nginx 反向代理 Google Fonts ,优化网站在国内的访问速度

Google Fonts 是于2010年上线的免费网页字体托管服务。Google Fonts 上面的字体全都是免费的,开发者可以使用 Google Fonts 来装饰个人、企业网站,以达到更好的显示效果。先看一下 Google Fonts 的官方介绍:

About Google Fonts

A web with web fonts is more beautiful, readable, accessible and open.

Google Fonts makes it quick and easy for everyone to use web fonts, including professional designers and developers. We believe that everyone should be able to bring quality typography to their web pages and applications.

Our goal is to create a directory of web fonts for the world to use. Our API service makes it easy to add Google Fonts to a website in seconds. The service runs on Google's servers which are fast, reliable and tested. Google provides this service free of charge.

Open Source Fonts

All of the fonts are Open Source. This means that you are free to share your favorites with friends and colleagues. You can even customize them for your own use, or collaborate with the original designer to improve them. And you can use them in every way you want, privately or commercially — in print, on your computer, or in your websites.

We are working with designers around the world to publish quality typeface designs that are made for the web. If you are a type designer and would like to discuss this, please get in touch.

Many of Google's own web pages are already using Google Fonts, such as Google's About page and Google's World Wonders Project which use Open Sans.

-— The Google Fonts Team

毋庸置疑,Google Fonts 是非常好用的一个服务。字体数量之多而且又是开源免费的,可谓是不可多得的。可是,有一件很不幸的事是,Google 现在一直处于被墙的状态。而 Google Fonts 服务使用的域名也被墙了。所以导致了在没有翻墙的情况下,Google Fonts 完全无法使用。而且也会导致使用了 Google Fonts 的网站在国内访问时异常缓慢。其根本原因就是 Google Fonts 被墙了。

所幸的是,国内有个360的 Google Fonts 镜像,360网站卫士常用前端公共库CDN服务,这个镜像对于没有使用 HTTPS 的网站来说还是相当好用的。但是如果你的站点使用了 HTTPS 的话,那就悲催了。因为这个镜像不支持 HTTPS 。

如果真的想使用 Google Fonts 的话,而且不想被墙的话,也是有办法的。

技术难度最低而且最笨的方法就是把 Google Fonts 的 CSS 文件和字体文件下载到网站服务器上面,然后再引进页面就行。

但是这种做法有一个缺点就是,Google Fonts 的 CSS 文件并不是一成不变的。它是会根据 UA 生成不同的 CSS 文件。所以,如果你只是简单的把 Google Fonts 的 CSS 下载下来而已,那么就享受不到这种高级的服务了。再者,要一个一个下载字体文件,也是挺麻烦的一件事。

如果你手头有一台国外服务器的话,那么,我们可以使用 Nginx 反向代理来解决这个问题。


关于 Nginx ,我就不介绍了。要顺利的完成反代有一个必要的前提,就是,你必须有一个可以正常访问 Google Fonts 的服务器,还有要有一个域名。如果你的服务器在国内的话,那么是没用的。因为一样是被墙的。另外有一点要注意的是,服务器最好网络线路要好,服务器网络太差也会影响网页加载速度。好了,废话不多说了。

安装Nginx

对于 Linux 系统来说,直接到 Linux 官网下载源码,然后自己编译安装。(如果已经安装了 Nginx 的话,请确保之前安装的时候有顺便安装HttpSubsModulehttp_spdy_modulehttp_ssl_module 模块,如果没有的话,也请先卸载之前安装的 Nginx 然后重新按照下面的教程安装一次。)

mkdir /home/download  
cd /home/download  
wget http://nginx.org/download/nginx-1.7.6.tar.gz  
tar -xvf nginx-1.7.6.tar.gz  

需要注意的是,我们接下来在编译安装之前要先配置一下 Nginx ,需要额外安装一个 HttpSubsModule 模块,再添加两个跟 SSL 有关的模块。

git clone git://github.com/yaoweibin/ngx_http_substitutions_filter_module.git  
cd nginx-1.7.6  
./configure --add-module=/home/download/ngx_http_substitutions_filter_module --with-http_spdy_module --with-http_ssl_module

如果这个阶段有报错的话,请查看系统是否缺了某些依赖,然后自行安装。如果一路顺畅没有错误的话(如下图),就直接开始编译

./configure
make  
make install  
编译过程
安装过程

至此, Nginx 就安装成功了。此时 Nginx 安装在 /usr/local/nginx 中,这时候我们如果要启动 Nginx 或者重启 Nginx 的话都要执行 /usr/local/nginx/sbin/nginx 类似这样的命令。为了简化这个启动步骤,我们可以编写一个 /etc/init.d/nginx 文件,使得启动 Nginx 跟启动一个服务一样那么简单。

vim /etc/init.d/nginx  

然后把下面的代码粘贴在这个新建的文件中:(以下代码适用于 CentOS 系统)

#!/bin/sh
#
# nginx - this script starts and stops the nginx daemin
#
# chkconfig:   - 85 15 
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /usr/local/nginx/conf/nginx.conf
# pidfile:     /usr/local/nginx/logs/nginx.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

nginx="/usr/local/nginx/sbin/nginx"  
prog="nginx"

NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"

lockfile=/var/lock/subsys/nginx

start() {  
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {  
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {  
    configtest || return $?
    stop
    start
}

reload() {  
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}

force_reload() {  
    restart
}

configtest() {  
  $nginx -t -c $NGINX_CONF_FILE
}

rh_status() {  
    status $prog
}

rh_status_q() {  
    rh_status >/dev/null 2>&1
}

case "$1" in  
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac  

注意,如果你的 Nginx 不是安装在 /usr/local/nginx 上的话,那么应该修改这个 nginx="/usr/local/nginx/sbin/nginx"NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf" 为正确的位置。

如果你的服务器系统为 Ubuntu 的话,请参考这个文件:https://raw.githubusercontent.com/JasonGiedymin/nginx-init-ubuntu/master/nginx

保存完该文件以后,更新该文件的权限,然后再将 Nginx 设置为开机启动:

chmod +x /etc/init.d/nginx  
chkconfig nginx on  

查看一下是否成功执行:

chkconfig --list nginx  
nginx           0:off   1:off   2:on    3:on    4:on    5:on    6:off  

如果显示结果是这样的话就表明成功设置开机自启动了。然后再执行

service nginx start  
Starting nginx:                                            [  OK  ]

成功启动 Nginx 。接下来我们要配置 Nginx 的设置文件,开始反代 Google Fonts 。

先创建一个 vhost 文件夹,然后编辑 /usr/local/nginx/conf/nginx.conf文件:

cd /usr/local/nginx/conf  
mkdir vhost  
vim nginx.conf  

然后在 nginx.conf 这个文件中的 http{} 中添加一行代码:

http {  
    include /usr/local/nginx/conf/vhost/*.conf;

    ...
}

这一行代码的作用是引入 /usr/local/nginx/vhost 目录下面的所有 .conf 文件,这样在这个 vhost 文件夹创建的文件都可以被正确的解析到。

保存该文件,然后进入 vhost 文件夹,创建 googlefont.conf 文件,把下面的代码粘贴进去:

# 反代的 Google fonts CSS 文件,http模式的
server {  
        listen 80;
        server_name google-fonts.xxx.com;
        location / {
                proxy_pass http://fonts.googleapis.com;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Via "nginx";
                proxy_set_header Accept-Encoding "";
        }
        subs_filter_types text/css;
        subs_filter 'fonts.gstatic.com' 'google-fonts-static.xxx.com';
}
# CSS文件的 HTTPS 模式的
server {  
        listen 443 ssl spdy;
        ssl_certificate /etc/ssl/server.crt;
        ssl_certificate_key /etc/ssl/server.pem;
        server_name google-fonts.xxx.com;
        location / {
                proxy_pass https://fonts.googleapis.com;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Via "nginx";
                proxy_set_header Accept-Encoding "";
        }
        subs_filter_types text/css;
        subs_filter 'fonts.gstatic.com' 'google-fonts-static.xxx.com';
}
# 反代 Google fonts 的字体文件。HTTP模式的
server {  
        listen 80;
        server_name google-fonts-static.xxx.com;
        location / {
                proxy_pass http://fonts.gstatic.com;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Via "nginx";
        }
}
# 字体文件的 HTTPS 模式的。
server {  
        listen 443 ssl spdy;
        ssl_certificate /etc/ssl/server.crt;
        ssl_certificate_key /etc/ssl/server.pem;
        server_name google-fonts-static.xxx.com;
        location / {
                proxy_pass https://fonts.gstatic.com;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Via "nginx";
        }
}

以上代码包含了 HTTP 和 HTTPS 两种。如果你不需要 HTTPS 的话,自行把 HTTPS 部分的代码删去即可。如果你有用到 HTTPS 的话请自行修改 ssl_certificatessl_certificate_key 这两个的具体路径,即 SSL 证书和密钥的文件位置。如果没有买 SSL 的话也可以自签名证书的,这个请自己Google 查阅教程。

其中, server_name 部分需要替换成你自己的域名。请自行替换。除了 server_name 之外还要注意 subs_filter 'fonts.gstatic.com' 'google-fonts-static.xxx.com'; 这一行,也需要替换。

googlefont.conf 这个文件修改完保存之后,便可以重启一下 Nginx 试验一下效果了:

service nginx restart  

如果这个过程有报错的话,请查看你的 Nginx 配置文件是否有语法错误,或者有没有一些必须的模块没有安装。排除完所有问题之后,重启 Nginx 后便可以试试是否能成功反代了。

我们先找一个被墙了的 Google Fonts 的 CSS 链接:

http://fonts.googleapis.com/css?family=Open+Sans:300,700,400  

在国内的网络环境下应该是没办法打开这个链接的。但是,换成我们的域名之后,应该就可以打开了:

http://google-fonts.xxx.com/css?family=Open+Sans:300,700,400  

其中 xxx.com 为你的域名。也就是说,使用我们自己的反代服务器的话,就只是把 fonts.googleapis.com 这部分替换成我们刚刚设置的域名即可。在本文中为 xxx.com ,所以最终效果为上面说显示的。

访问 http://google-fonts.xxx.com/css?family=Open+Sans:300,700,400 如果能够看到一个CSS文件则表示 Google Fonts 的 CSS 文件部分反代成功。接下来还要验证一下字体文件能否反代成功。

验证字体文件是否反代成功方法是直接打开 CSS 文件中的字体链接。在没有反代之前,访问 http://fonts.googleapis.com/css?family=Open+Sans:300,700,400 得到的 CSS 文件的格式应该是类似这样的:

/* cyrillic-ext */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300;
  src: local('Open Sans Light'), local('OpenSans-Light'), url(http://fonts.gstatic.com/s/opensans/v10/DXI1ORHCpsQm3Vp6mXoaTSUUniRZcd_wq8DYmIfsw2A.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: 300;
  src: local('Open Sans Light'), local('OpenSans-Light'), url(http://fonts.gstatic.com/s/opensans/v10/DXI1ORHCpsQm3Vp6mXoaTeXREeHhJi4GEUJI9ob_ak4.woff2) format('woff2');
  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

可以看到字体文件的链接在 http://fonts.gstatic.com 这个域名下面。而经过我们反代过的 CSS 文件应该是这样的:

/* cyrillic-ext */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300;
  src: local('Open Sans Light'), local('OpenSans-Light'), url(http://google-fonts-static.xxx.com/s/opensans/v10/DXI1ORHCpsQm3Vp6mXoaTSUUniRZcd_wq8DYmIfsw2A.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: 300;
  src: local('Open Sans Light'), local('OpenSans-Light'), url(http://google-fonts-static.xxx.com/s/opensans/v10/DXI1ORHCpsQm3Vp6mXoaTeXREeHhJi4GEUJI9ob_ak4.woff2) format('woff2');
  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

可以看出字体文件的链接都被转化成 http://google-fonts-static.xxx.com 这样了。访问其中一条字体链接 http://google-fonts-static.xxx.com/s/opensans/v10/DXI1ORHCpsQm3Vp6mXoaTSUUniRZcd_wq8DYmIfsw2A.woff2 如果可以正常下载该字体文件则表示字体文件部分反代成功。这样我们就可以放心的用我们自己的 Google Fonts 镜像了。以后需要用到新的 Google Fonts 字体就直接到 Google Fonts 官网找字体的链接,再把链接的域名换成我们自己的域名就行了。这样就完美的完成了 Google Fonts 的反向代理,加快了网站的访问速度。


总结

其实整个反代的过程不麻烦,技术难度不高,一个最核心的思想是,反代 CSS 文件,然后把CSS文件里面有关字体文件的域名全都替换成我们自己的域名,然后再把CSS文件返回给浏览器,浏览器解析CSS文件,然后从我们自己的域名下面获取 Google Fonts 的字体文件。

利用这个思路,其实我们也可以做出 Twitter/Google/Facebook 的反代,其原理大致一样,都是将所有外部资源改成从我们自己的域名下面获取。

Nginx 确实很强大,看来真的要用心的去研究一下才行。:)

Comments is loading...

Comments is loading...