我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本文是系列文章,上一篇文章地址是:https://newsn.net/say/cors-jsonp.html 。本文主要说两个高级点的跨域话题,即:接口cookie传递及不使用jsonp如何设置跨域。

苏南大叔:跨域 ajax 请求之 cors 原理解析 - 跨越cors
跨域 ajax 请求之 cors 原理解析(图1-1)

原理描述

目前的最新浏览器下面,都可以不使用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头到客户端,苏南大叔下面的demophp版本的。

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 类似这样的,httphttps一定要区分好,端口号如果有的话,也一定要带上。当然了,这些headerphp发出的,还是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,似乎是更好的解决方案。

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   ajax    cors