跨域 ajax 请求之 cors 原理解析
发布于 作者:苏南大叔 来源:程序如此灵动~本文是系列文章,上一篇文章地址是:https://newsn.net/say/cors-jsonp.html 。本文主要说两个高级点的跨域话题,即:接口cookie传递及不使用jsonp
如何设置跨域。
原理描述
目前的最新浏览器下面,都可以不使用jsonp
来跨域了,就是说还使用传统的json
。当然了,前端请求的时候,要特殊写上点代码,后端处理的时候,也需要发出特殊的header
头,整个过程才能畅通。
另外,默认情况下,跨域的话,是不会发送cookie
的。而服务器端接口需要做权限判断之类的话,就需要cookie
上的支持。这个时候,同样需要做些设置。
前端代码
好了,先整体的来说。下面是前端相关代码,以jquery为例:
$.ajaxSetup({
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
这个非常简单,设置上这个之后,页面上所有的ajax请求都不用特殊写代码了,都会默认支持跨域传递cookie。是不是很简单?
如果你不这么整体的来写的话,每个ajax请求都需要额外添加crossDomain和xhrFields这2个属性。貌似真心不是很方便。
$.ajax({
url:'https://newsn.net/',
type:'GET',
dataType:'json',
success:function (data) {},
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
后端代码
后端服务器端,需要发送这些header
头到客户端,苏南大叔下面的demo
是php
版本的。
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:GET,POST,OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Max-Age:864000
这里要特别强调的是:Access-Control-Allow-Origin
这个属性,设置为*
肯定可以。不过,这就非常不安全了,因为这个就是来控制到底哪个域名可以跨域访问接口的。所以,这个属性,一定要设置为具体的网址才好,注意要设置为 https://yourdomain.com:port
类似这样的,http
和https
一定要区分好,端口号如果有的话,也一定要带上。当然了,这些header
是php
发出的,还是nginx发
出的,都是可以的。
nginx
代替php
发出特定header
可能,nginx
发出header
似乎更合适一些。那么下面贴出的就是可能的nginx
设置。
参考文章:https://enable-cors.org/server_nginx.html
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
#
# Om nom nom cookies
#
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers **should** be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
下面的是另外一个我使用过的配置:
server {
listen 443 ssl;
server_name blogd.newsn.net;
ssl_certificate /application/nginx/ssl/newsn.net.crt;
ssl_certificate_key /application/nginx/ssl/newsn.net.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
access_log /data/logs/nginx/cloud/access.log json;
error_log /data/logs/nginx/cloud/error.log error;
set $ACAO 'http://blog.newsn.net https://blog.newsn.net';
if ($http_origin ~* ^(http|https)://blog\.newsn\.net$) {
set $ACAO $http_origin;
}
add_header Access-Control-Max-Age 864000;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin '$ACAO';
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
location /robots.txt {
root html;
}
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Max-Age 864000;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin '$ACAO';
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
return 204;
}
proxy_pass http://blog-portal;
proxy_http_version 1.1;
proxy_set_header Connection "";
#proxy_set_header Host $host:$server_port;
proxy_set_header Host $host;
#proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name blog.newsn.net;
rewrite ^(.*) https://blog.newsn.net$1 permanent;
}
结语
苏南大叔觉得,鉴于nginx
设置如此繁杂,我们还是老老实实的用php
输出header
吧,其实蛮简单的。是不是?据说,上述设置中的js部分在ie低版本浏览器下面是不ok的。那么如果我们需要兼容ie
低版本的话,那么还是老老实实的写不安全的jsonp
,似乎是更好的解决方案。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。