nginx缓存、跨域 CORS与防盗链设置(2)
3.3 缓存功能
反向代理可以缓存静态资源。
当客户端再次请求访问相同资源时,反向代理可以直接返回缓存中的响应,无需二次请求,减少对后端服务器的请求压力,并加快响应速度。
proxy_cache zone_name on | off; 默认off
#指明调用的缓存,或关闭缓存机制;Context:http, server, location
#zone_name 表示缓存的名称.需要由proxy_cache_path事先定义
proxy_cache_key string;
#缓存中用于“键”的内容,默认值:proxy_cache_key $scheme$proxy_host$request_uri;
proxy_cache_valid [code ...] time;
#定义对特定响应码的响应内容的缓存时长,定义在http{...}中
示例:
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_path;
#定义可用于proxy功能的缓存;Context:http 必须放在http语句中
proxy_cache_path path [levels=levels] [use_temp_path=on|off]
keys_zone=zone_name:size [inactive=time] [max_size=size] [manager_files=number]
[manager_sleep=time] [manager_threshold=time] [loader_files=number]
[loader_sleep=time] [loader_threshold=time] [purger=on|off]
[purger_files=number] [purger_sleep=time] [purger_threshold=time];
#示例:在http配置定义缓存信息
proxy_cache_path /var/cache/nginx/proxy_cache #定义缓存保存路径,proxy_cache会自动创建
levels=1:2:2 #定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=2^20=1048576个目录
keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key和metadata(如:使用次数),一般1M可存放8000个左右的key
inactive=120s #缓存有效时间
max_size=10g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值
#调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
proxy_cache proxycache;
proxy_cache_key $request_uri; #对指定的数据进行MD5的运算做为缓存的key
proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m; #除指定的状态码返回的数据以外的缓存多长时间,必须设置,否则不会缓存
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ; #默认是off
#在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端#示例
proxy_cache_use_stale error http_502 http_503;
proxy_cache_methods GET | HEAD | POST ...;
#对哪些客户端请求方法对应的响应进行缓存,GET和HEAD方法总是被缓存
proxy_cache_path /data/nginx/proxycache levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g;
#http 语句
#1:1:1 16个二进制 2^16/2^16/2^16 2^48
server {
listen 80;
proxy_cache proxycache;
proxy_cache_key $request_uri;
#proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 302 301 10m;
#proxy_cache_valid any 5m;
server_name www.kgc.com;
root /data/nginx/pc;
location / {
root /data/nginx/pc;
}
location /api {
proxy_pass http://192.164.91.101:9527;
}
location ~* \.(jpg|png|gif|html)$ {
proxy_pass http://192.164.91.102;
}
}
清理缓存
方法1: rm -rf 缓存目录
方法2: 第三方扩展模块ngx_cache_purge
四、 Nginx配置跨域 CORS
4.1 跨域的定义
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。通常不允许不同源间的读操作。
4.2 同源的定义
如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源。
与 URL http://store.company.com/dir/page.html 的源进行对比的示例:
-
http://store.company.com/dir2/other.html 同源
-
https://store.company.com/secure.html 不同源,协议不同
-
http://store.company.com:81/dir/etc.html 不同源,端口不同
-
http://news.company.com/dir/other.html 不同源,主机不同
4.3 不同源的限制
-
Web 数据层面,同源策略限制了不同源的站点读取当前站点的 Cookie 、 IndexDB 、 LocalStorage 等数据;
-
DOM 层面,同源策略限制了来自不同源的 JavaScript 脚本对当前 DOM 对象读和写的操作;
-
网络层面,同源策略限制了通过 XMLHttpRequest 等方式将站点的数据发送给不同源的站点。
4.4 Nginx 解决跨域的原理
浏览器的同源策略限制了跨域请求,但当使用 Nginx 作为代理服务器时,浏览器发送的请求实际上是发送到与前端页面同源的 Nginx 服务器。然后 Nginx 将请求转发到真正的目标服务器,目标服务器返回的响应再通过 Nginx 返回给浏览器。从浏览器的角度看,它只与同源的 Nginx 服务器进行交互,从而绕过了 CORS 限制
4.5 案例
前端 server 的域名为:fe.server.com
后端服务的域名为:dev.server.com
现在在 fe.server.com 对 dev.server.com 发起请求一定会出现跨域。
现在我们只需要启动一个 Nginx 服务器,将 server_name 设置为 fe.server.com 然后设置相应的 location 以拦截前端需要跨域的请求,最后将请求代理回 dev.server.com 。
如下面的配置:
server {
listen 80;
server_name fe.server.com;
location / {
proxy_pass dev.server.com;
proxy_set_cookie_domain target-domain.com your-domain.com;
proxy_set_header Host target-domain.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 可选的配置,用于处理响应头
proxy_set_header Access-Control - Allow - Origin http://fe.server.com;
proxy_set_header Access-Control - Allow - Methods GET,POST,PUT,DELETE;
proxy_set_header Access-Control - Allow - Headers Content - Type,Authorization;
}
}
配置解析:
-
proxy_set_header
-
Host backend - domain.com:设置转发请求的Host头信息。这是因为后端服务器可能会根据Host头来区分不同的虚拟主机或服务,所以需要将正确的Host信息传递给后端服务器,使其能够正确处理请求。
-
X-Real-IP $remote_addr和X-Forwarded-For $proxy_add_x_forwarded_for:这两个指令用于传递客户端的真实 IP 地址。$remote_addr是 Nginx 记录的客户端 IP 地址,$proxy_add_x_forwarded_for是一个包含了客户端 IP 以及中间代理服务器 IP(如果有的话)的变量。这样后端服务器可以获取到正确的客户端 IP 信息,用于日志记录、访问控制等目的。
-
Origin http://frontend - domain.com:这是关键的一个设置,用于在转发请求时,将Origin头信息设置为前端页面的域名。后端服务器在收到这个请求时,会认为请求来自于同源的http://frontend - domain.com,从而避免了 CORS 限制。这样后端服务器就可以正常处理请求并返回响应,响应会通过 Nginx 再返回给浏览器。
-
proxy_set_header Access-Control - Allow - Origin
这个指令用于在 Nginx 作为代理服务器返回响应时,设置Access - Control - Allow - Origin响应头。通过将其设置为前端页面的域名(http://frontend - domain.com),浏览器会认为这个响应是来自同源的服务器,从而允许前端 JavaScript 代码访问这个响应,有效地绕过了 CORS 限制。
-
proxy_set_header Access-Control - Allow - Methods
用于设置Access - Control - Allow - Methods响应头,指定允许的 HTTP 请求方法。在这里列举了GET、POST、PUT和DELETE,表示后端服务器允许前端通过这些方法进行跨域请求。可以根据实际的后端 API 支持的方法进行调整。
-
proxy_set_header Access-Control - Allow - Headers
设置Access - Control - Allow - Headers响应头,指定允许的请求头。Content - Type头通常用于指定请求或响应的内容类型,如application/json或text/plain等;Authorization头用于传递认证信息,如令牌或用户名 / 密码等。这确保了前端在跨域请求中可以发送这些必要的请求头,并且后端会认可这些请求头。
-
这样可以完美绕过浏览器的同源策略:fe.server.com 访问 Nginx 的 fe.server.com 属于同源访问,而 Nginx 对服务端转发的请求不会触发浏览器的同源策略。
五、Nginx防盗链设置
5.1 什么是盗链
-
在实际生产过程中,我们线上的图片等静态资源,经常会被其他网站盗用,他们发大财的同时,成本却是我们在买单,下面来说下,如何杜绝这种行为。
-
应该说只要是静态资源都是可以防盗链的,只需要在Server字段加上几行代码即可。众所周知网站出名了后,会有各种刁民来找茬的,最常见的就是爬你网站的东西。
-
关于防盗链这里不得不提一下网页的加载顺序是先加载HTML相关的内容,然后解析HTML的内容,那些需要加载图片,那些需要加载文件,是逐步加载的,所以可以在加载静态资源的时候做防盗链的操作,例如:在加载图片的时候直接跳转去其他链接,或者直接返回404,403等错误代码,拒绝它的请求。
如何区分哪些是不正常的用户?
-
HTTP Referer是Header的一部分,当浏览器向Web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器借此可以获得一些信息用于处理,例如防止未经允许的网站盗链图片、文件等。因此HTTP Referer头信息是可以通过程序来伪装生成的,所以通过Referer信息防盗链并非100%可靠,但是,它能够限制大部分的盗链情况.
-
比如在www.google.com 里有一个 www.baidu.com 链接,那么点击这个www.baidu.com ,它的header 信息里就有:Referer=http://www.google.com
5.2 Referer解析
-
HTTP 协议中有一个用来表示“页面或资源”来源的“请求头”,这个请求头叫做 Referer --> Referer是表示请求是从哪个网址发出的防盗链功能基于HTTP协议支持的 Referer 机制,通过Referer跟踪来源,对来源进行识别和判断
5.3 配置防盗链案例
为了模拟盗链,让192.168.166.9为网站服务站点,192.168.166.10访问192.168.166.9进行盗链。
修改Nginx的字符集以支持中文:
charset utf-8;
修改 192.168.166.10 Nginx 默认访问文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>产生盗链</title>
</head>
<body>
<a href='http://192.168.166.9/photos/1.png'>站点</a>
</body>
</html>
此时在浏览器输入192.168.166.10,可以正常访问192.168.166.9站点的图片资源。
如果不想被盗链,则对192.168.166.9站点服务修改Nginx配置文件,防盗链的配置可以在任意的 location 模块下设置,不能在 server 下,不想让别人盗链哪个资源就在那个资源的 location 模块下设置防盗链。
防盗链设置格式:
valid_referers none | blocked | server_names | strings ....;
-
--none:允许没有http_refer的请求访问资源,检测 Referer 头域不存在的情况,则可以访问。
-
--blocked:检测 Referer 头域的值被防火墙或者代理服务器删除或伪装的情况。这种情况该头域的值不以 “http://” 或 “https://” 开头。允许不是http://开头的,不带协议的请求访问资源。
-
--server_names :只允许指定ip/域名来的请求访问资源(白名单)。可设置一个或多个 URL ,检测 Referer 头域的值是否是这些 URL 中的某一个。在生产环境中尽量使用域名,不使用ip。
举例
valid_referers 192.168.44.101;
if ($invalid_referer) {
return 403;
}
192.168.166.9设置防盗链
server {
listen 80;
server_name localhost;
location / {
root /usr/local/nginx1273/html;
index index.html index.htm;
}
location ~* \.(js|img|css|png)${
valid_referers 192.168.166.9; #只允许192.168.166.9访问静态资源,其他人访问则会返回403
if ($invalid_referer){
return 403;
}
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location =/50x.html {
root html;
}
}
5.4 测试
浏览器测试
用192.168.166.10去访问,css等静态资源返回403,获取不到数据。
点击”站点“,跳转到192.168.166.9站点资源是显示: