Nginx 解决请求跨域 与 配置 gzip 压缩
目录
关于什么是跨域?可以参考《JavaScript 跨域请求解决方式汇总》,本文只介绍如何使用 Nginx 解决跨域请求。
搭建跨域请求环境
1、解决跨域之前,先还原一个跨域请求的场景,之后再通过 Nginx 来解决跨域。
2、提供一个简单的 HelloWorld 应用,浏览器访问后进入主页 index.jsp 如下:http://192.168.1.20:8080/HelloWorld/。(192.168.1.20是本机的IP地址,所有的操作都是本机中模拟)
3、然后再提供一个应用来访问上面的 HelloWorld 应用,这里直接在 webStorm 中通过 js 中的 ajax 来请求,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title></title>
<script src="https://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
$("button").click(function () {
$.ajax({
url: "http://192.168.1.20:8080/HelloWorld/",
success: function (data) {
console.log("success:" + JSON.stringify(data));
},
error: function (data) {
console.log("error:" + JSON.stringify(data));
}
});
});
});
</script>
</head>
<body>
<button type="button" style="font-size: 20px">跨域请求</button>
</body>
</html>
已拦截跨源请求:同源策略禁止读取位于 http://192.168.1.20:8080/HelloWorld/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
4、从 http://192.168.1.20:55555/liaisonStation/test2.html 的 js 中去请求 http://192.168.1.20:8080/HelloWorld/ ,这是典型的端口不同而导致的跨域请求被同源策略限制。
5、其它解决跨域的方式可以参考《JavaScript 跨域请求解决方式汇总》,这里只介绍使用 Nginx 。
Nginx 解决跨域
1、现在开始通过配置 nginx.conf 来解决上面的跨域问题,为了方便,这里选择在 windows 系统上操作,Linux 系统同理。
2、没有下载安装 Nginx 的可以参考《Nginx》。修改 nginx.conf 配置文件如下:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
#本虚拟主机域名,多个时使用空格隔开,默认为 localhost,修改为跨域请求目标的域名,如 www.w3school.com.cn
server_name 192.168.1.20;
#charset koi8-r;
#access_log logs/host.access.log main;
#设置哪些域名可以跨域请求此虚拟主机,因为从 js 中请求 nginx 时,本身也是跨域请求
# "*" 表示允许所有的 "源" 进行请求,也可指定只允许某个具体的源可以访问
add_header Access-Control-Allow-Origin *;
location / {
root html;
index index.html index.htm;
proxy_pass http://192.168.1.20:8080; #反向代理
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
在默认的基础上,修改了第 37、44、48 行。
1)第 37 行:因为页面直接请求 HelloWorld 时被同源策略限制了,于是现在页面请求nginx代理服务器,代理服务器代理 HelloWorld,所以 nginx 虚拟主机的域名(server_name)应该和目标服务器 HelloWorld 的域名一致。
2)而且源(本例为 55555端口的应用)的端口、HelloWorld 的端口以及 Nginx 监听的端口(listen) 可以全部都不同。(本例源是 55555 端口,Nginx 监听的是 80 端口,目标服务器的 8080 端口)
3)因为一个 server 下可以有多个 location,所以也可以配置多个 server_name,空格隔开。
3、start .\nginx.exe 启动 nginx.exe 。显然如果代理成功,此时浏览器输入 http://localhost/HelloWorld/ 也要能访问原来的 http://localhost:8080/HelloWorld/ 才对。
4、修改源 55555 端口的应用 js 中的 url 地址:
...
$.ajax({
//不再直接请求目标服务器,而是请求代理服务器
url: "http://localhost:80/HelloWorld/",
success: function (data) {
console.log("success:" + JSON.stringify(data));
},
error: function (data) {
console.log("error:" + JSON.stringify(data));
}
});
...
5、直接停止 nginx : .\nginx.exe -s stop,然后再次启动:start .\nginx.exe,现在进行跨域问题已经解决:
配置 gzip 压缩
1、GZIP
是规定的三种标准 HTTP 压缩格式之一,对于文本文件,GZip
的效果非常明显,开启后传输所需流量大约会降至 1/4 ~ 1/3
。
2、目前绝大多数的网站都在使用 GZIP
传输 HTML
、CSS
、JavaScript
等资源文件,主流的浏览器也都支持 gzip 压缩,可以通过请求头中的 Accept-Encoding
查看浏览器支持的压缩类型。
随便打开一个网站,即可以在请求头中看到
Accept-Encoding(接受编码).
3、启用 gzip 压缩需要客户端和服务端同时支持,如果客户端支持 gzip 解析,那么只要服务端能够返回 gzip 的文件就可以启用gzip了, 可以通过 nginx 的配置来让服务端支持 gzip。
4、如下所示为请求本机应用中的 http://localhost/HelloWorld/jquery-3.4.0.js 文件,默认情况下显然它是没有压缩的。没有压缩时响应头中会有 Content-Length:***,压缩后响应头中会有 Content-Encoding:***:
5、下面使用 nginx 反向代理目标服务器,然后在 nginx.conf 配置 gzip 压缩:
...
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
gzip on;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_min_length 100;
gzip_types text/csv text/xml text/css text/plain text/javascript application/javascript application/x-javascript application/json application/xml;
server {
listen 80;
#本虚拟主机域名,多个时使用空格隔开,默认为 localhost,修改为跨域请求目标的域名,如 www.w3school.com.cn
server_name 192.168.1.20;
#charset koi8-r;
...
gzip:开启或者关闭
gzip
模块,默认值为off
,可配置为on / off
gzip_http_version:启用
GZip
所需的HTTP
最低版本,默认值为HTTP/1.1
gzip_comp_level:压缩级别,级别越高压缩率越大,当然压缩时间也就越长(传输快但比较消耗 cpu),默认值为
1
,压缩级别取值为1-9。
gzip_min_length:设置允许压缩的页面最小字节数,
Content-Length
小于该值的请求将不会被压缩,默认值0。
当设置的值较小时,压缩后的长度可能比原文件大,建议设置1000
以上(这里是故意降低了阀值)。gzip_types:要采用 gzip 压缩的文件类型 (
MIME
类型),默认值为text/html
(默认不压缩js
/css
)。(注意:需要压缩的类型都可以通过响应头中的 Content-Type 查看,如 js 类型为 Content-Type:application/javascript,需要压缩 js 时,则这个值必须配置在 gzip_types 中,同时满足其他条件时,就会生效压缩。)
6、此时重启 nginx : .\nginx.exe -s reload,再次访问时如下,没有压缩时响应头中会有 Content-Length:***,压缩后响应头中会有 Content-Encoding:***:
如上所示:Content-Encoding:gzip 表示内容为 gzip 压缩。
注意:如上所示为下载的最新版 JQuery-3.4.0.js,大小为 273KB,所以上面配置 gzip_min_length 故意设置为了 100,如果设置成 gzip_min_length 1000;,那么就不会对它进行压缩了。
nginx 常用命令
start nginx.exe //启动
nginx.exe -s reload //重启
nginx.exe -s stop //快速停止
nginx.exe -s quit //完整有序停止
没配置环境变量时,在 nginx.exe 所在目录下使用命令行即可。