写在前面

前面学习的都是一些比较枯燥的内容,接下来学习一下较为有趣的配置,如使用Nginx来设置防盗链、防爬虫和虚拟目录等,学习和掌握这些有趣的知识可以提升自己的综合能力。

防盗链

为什么需要防盗链?现在随着自媒体的发展,很多人开始以博流量为由,各种复制别人发布的文章,更有甚至将其标为原创来盗取他人的劳动成果,因此防盗链的设置显得尤为重要。

一般来说,当开发者对该网站做好防盗链之后,其他网站盗链本站的图片就会全部失效无法显示,但是如果用户是通过浏览器来访问本网站或者直接访问图片地址时,这些图片依旧是可以正常显示,且可以右键下载到本地,所以这只是对网站做的防盗链,对于用户还是挺友好的。

这是使用的是ngx_http_referer_module模块,通常使用它来阻挡非法的域名请求,请注意伪装Referer头部其实非常简单,因此这个模块只能用于阻挡大部分非法请求,而有些正常请求,如用户直接访问是不会携带Referer头部,但是这种情况是应当被允许的,因此不能拒绝来源Referer头部为空的请求。

在vhost文件夹下面新建一个hero.com.conf的配置文件,其中的内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 92;
server_name localhost;

location / {
root D:\Application\Nginx-1.18.0\static;
index index.html;
}

location ~* \.(gif|jpg|swf|bmp|jpeg|png)$ {
valid_referers none blocked *.store.com;
if ($invalid_referer) {
return 403;
}
}
access_log D:\Application\Nginx-1.18.0\logs\access_log.log;
}

解释一下上述代码的含义:首先我们这个Nginx服务监听本地的92端口,然后设置网站根目录为D:\Application\Nginx-1.18.0\static,注意这里必须使用绝对路径,然后设置网站首页为index.html文件,接着定义一个location,里面用于匹配图片,注意下面的一段代码:

1
2
3
4
valid_referers none blocked *.store.com;
if ($invalid_referer) {
return 403;
}

其中valid_referers用来定义一个合法访问的白名单,其实就是判断请求中的referer来源;none表示通过浏览器直接访问图片地址,这种情况下请求中是没有referer的,但是这种请求通常也是允许访问的;blocked表示当请求中的referer不为空时,但是它的内容被防火墙或者代理服务器给删除了,这种请求通常也是允许访问的。*.store.com是被允许访问的域名,可以使用通配符。$invalid_referer是一个变量,用于判断valid_referers的结果是否合法,如果判断不合法则就返回403,当然开发者也可以使用重定向来自定义不合法时的显示信息。

请注意,上述localhost*.store.com不能是同一台机器,否则会出现图片访问不到的情况,因为你对这台机器设置了防盗链,又使用这台机器来返回防盗链图片,这是不可能的。

上面只是对某个server进行防盗链设置,如果想对整站做防盗链,只需将配置添加到http区块中。

防爬虫

其实这里的防爬虫也只是针对那些比较符合约定的爬虫,对于那些流氓爬虫,这里介绍的配置还是无法解决。

开发者只需在用户访问网站首页时进行设置即可实现目的,可以在server区块中添加如下配置:

1
2
3
4
5
6
location / {
if ($http_user_agent ~* "python|curl|java|wget|httpclient|okhttp") {
return 503;
}
# 正常处理逻辑
}

当然下面的配置也是可以的,因为user-agent种类较多:

1
2
3
4
5
6
location / {
if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot") {
return 403;
}
# 正常处理逻辑
}

虚拟目录

请注意Nginx是通过alias关键词来设置虚拟目录的,alias目录和root目录是有区别的,下面将详细进行分析:

(1)对于alias来说,它指定的目录是准确的,即location匹配访问path目录下的文件是直接在alias目录下查找的。

(2)对于root来说,它指定的目录是location匹配访问path目录的上一级目录,这个path目录必须真实存在于root指定目录下。

例子1,假设笔者配置的域名是www.envygo.com,且域名配置文件名称为envygo.com.conf,其中的代码为:

1
2
3
4
5
6
server {
listen 80;
server_name www.envygo.com;

access_log /usr/local/nginx/logs/think.log main gzip buffer=128k flush=5s;
}

为了访问http://www.envygo.com/book/main.html文件,如果开发者使用root目录这一方式,那么应当添加如下location片段:

1
2
3
location /book/ {
root /home/www/;
}

也就是说此时文件的实际存储路径为/home/www/book/main.html

如果使用alias虚拟目录这一方式,那么应当添加如下location片段:

1
2
3
location /book/ {
alias /home/www/book/;
}

注意使用alias虚拟目录时,后面的/home/www/book/最后面必须添加/表示这是一个目录,如果不加那么文件就无法查找的到。如果使用root,那么/home/www/最后面的/可加可不加,但是建议还是加,规范一下。


细心的你可能已经发现前面举的例子中,alias设置的目录名称和location匹配访问的path目录名称是一致的,这样就可以直接修改为root目录配置。但是在实际工作中,也经常会出现目录不一致情况,此时应该如何操作呢?

例子2,假设alias设置的目录名称和location匹配访问的path目录名称不一致,如下所示:

1
2
3
location /web/ {
alias /home/www/html/;
}

这样当开发者访问http://www.envygo.com/web/main.html的时候,Nginx就会去查找/home/www/html/main.html文件。注意此时就不能直接修改为root目录配置,因为/home/www/html/目录下是不存在web目录的,如果非要这么做的话,可以采用软链接的方式,即将/home/www/目录下的html目录软链接到web目录。先执行如下软连接操作:

1
ln -s /home/www/web /home/www/html

之后location中的代码修改为如下所示:

1
2
3
location /web/ {
root /home/www/;
}

综合上述分析,我们建议在location / 中采用root目录配置;在location /path 中采用alias虚拟目录配置。


(3)在alias虚拟目录配置中,如果location匹配的path目录后面不携带/,那么访问的url地址中这个path目录后面加不加/不影响访问,因为在访问时会自动加上/。但是如果location匹配的path目录后面携带了/,那么访问的url地址中这个path目录后面必须添加/,因为在访问时它不会自动加上/,故访问的时候就会失败。

例子3,下面例子中的location匹配的path目录后面没有携带/,那么

1
2
3
location /book {
alias /home/www/book/;
}

用户使用http://www.envygo.com/book或者http://www.envygo.com/book/都是可以访问的到。但是如果location匹配的path目录后面携带了/,那么

1
2
3
location /book/ {
alias /home/www/book/;
}

用户必须使用http://www.envygo.com/book/才能访问得到,使用http://www.envygo.com/book则会抛错。


(4)使用alias标签的目录块中不能使用rewrite重写的break,且alias指定目录的后面必须添加/,这一点不能忘记。

接下来将完整的展示一个配置信息,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server {
listen 80;
server_name www.envygo.com envygo.com;

location / {
root /home/www/;
}

location /book { # 匹配的path目录book不一定必须真实存在于 /home/www/html/目录中
alias /home/www/html/; # 注意最后的/ 必须加上,表示一个路径
}

location /movie { # 匹配的path目录movie必须真实存在于 /home/www/html/目录中
root /home/www/html/;
}

location ~.*\.(js|css|jpg|JPG|jpeg|JPEG|bmp|gif|GIF)$ {
access_log off; #日志过滤策略
}
access_log /usr/local/nginx/logs/think.log main gzip buffer=128k flush=5s;
}

当开发者访问http://www.envygo.com/index.html时,Nginx会去/home/www目录下查找index.html文件;访问http://www.envygo.com/book/test.html时,Nginx会去/home/www/html目录下查找test.html文件;访问http://www.envygo.com/movie/test.html时,Nginx会去/home/www/html/movie目录下查找test.html文件。