文本讨论关于接口开发中的跨域 CORS。html
CORS是一种浏览器协议,源于HTTP 请求的安全策略,在这个体系中的关键词有,同源策略,XMLHttpRequest,Ajax,和先后端分离。尤为是在目前业界先后端分离的大趋势下,跨域是一种常见的先后端开发通信(communicate)方式。html5
The basic idea behind CORS is to use custom HTTP headers to allow both the browser and the server to know enough about each other to determine if the request or response should succeed or fail.以上一段话参考 Cross-domain Ajax with Cross-Origin Resource Sharing/,主要含义是说CORS的核心思想是经过HTTP请求头通信,使得客户端和服务器端彼此决定请求和响应是否被成功接受。nginx
Using CORS这里有一篇关于跨域技术的完整阐述,感兴趣的能够阅读。git
CORS 协议的实现须要客户端和服务器端配合协做完成。也就是咱们一般所说的跨域设置。
The browser adds some additional headers, and sometimes makes additional requests, during a CORS request on behalf of the clientgithub
浏览器将CORS请求分红两类:简单请求(simple request)和非简单请求(not-so-simple request)。web
Microsoft API设计指导 中这么一段关于跨域的描述ajax
8.1.1. Avoiding preflightjson
Because the CORS protocol can trigger preflight requests that add additional round trips to the server, performance-critical apps might be interested in avoiding them. The spirit behind CORS is to avoid preflight for any simple cross-domain requests that old non-CORS-capable browsers were able to make. All other requests require preflight.后端
A request is "simple" and avoids preflight if its method is GET, HEAD or POST, and if it doesn't contain any request headers besides Accept, Accept-Language and Content-Language. For POST requests, the Content-Type header is also allowed, but only if its value is "application/x-www-form-urlencoded," "multipart/form-data" or "text/plain." For any other headers or values, a preflight request will happen.api
The spirit behind CORS is to avoid preflight for any simple cross-domain requests that old non-CORS-capable browsers were able to make
咱们提炼出简单请求的判断标准
1 )GET, HEAD or POST 三种请求
2) 不增长任何额外的请求头
3) POST 请求容许三种Content—Type: "application/x-www-form-urlencoded," "multipart/form-data" or "text/plain.
不符合简单请求的,均属于非简单请求。这么看来咱们平时常常使用的
Content-Type: application/json
显然是一种非简单请求头。
对于非简单请求,CORS 机制会自动触发浏览器首先进行 preflight(一个 OPTIONS 请求), 该请求成功后才会发送真正的请求。这里的 preflight 也能够被翻译为(预检)请求。
像上文中所说那样, 增长了自定义字段后,跨域请求就变成了一种带有 preflight 的非简单请求,所以会有下面的一种理解。
Access-Control-Allow-Headers是 preflight 请求中用来标识真正请求将会包含哪些头部字段,也就是下文中的自定义头部。这种方式是服务器端安全防范的一种。
这个设置是关因而否支持Cookies的
xhr.withCredentials = true; Access-Control-Allow-Credentials: true
//Access-Control-Allow-Origin:* public $arr_acao = [ '*' ]; //Access-Control-Allow-Methods public $arr_acam = [ 'POST', 'PUT', 'GET', 'DELETE', 'OPTIONS' ]; //Access-Control-Allow-Headers public $arr_acah = [ 'token', 'app-key', 'content-type', ]; header('Access-Control-Allow-Origin: '.implode(',', $this->arr_acao)); header('Access-Control-Allow-Methods: '.implode(',', $this->arr_acam)); header('Access-Control-Allow-Headers: '.implode(',', $this->arr_acah)); header("Access-Control-Max-Age: 86400"); if ($req->isOptions) { $code = "202"; $message = "Accepted"; header("HTTP/1.1 ".$code." ".$message); exit(); }
经过 Access-Control-Allow-Headers 设置自定义字段的方式,是一种安全策略,服务端要求请求头必须携带 'token', 'app-key','content-type'三个属性字段,缺一不可,不然请求不能达成。
origin 'http://xx.cn' has been blocked by CORS policy: Request header field timestamp is not allowed by Access-Control-Allow-Headers in preflight response.
location ~* \.(eot|ttf|woff|woff2|svg)$ { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers X-Requested-With; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; }
以上设置的前提是Nginix 开启了模块 ngx_http_headers_module
# # 用于nginx的开放式CORS配置 # location / { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # # 自定义标题和标题各类浏览器*应该*能够,但不是 # add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # # 有效期为 # add_header 'Access-Control-Max-Age' 22000; 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-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; }
Nginx中跨域,应用程序与web服务器存在耦合,增长了应用程序部署和扩展的复杂性,按需使用。
本文主要介绍了CROS的基本分类和常见的实现方案,对于同源策略,XMLHttpRequest请求等基础知识被没有过多涉及。简单请求和非简单请求的分类是重点。理解了这一点,就能理解什么场景浏览器会发起预检请求,并回复对应的响应。
咱们常说跨域设置是客户端和服务器端一块儿配合的结果,官方协议更倾向于让开发者对于跨域无感知,而浏览器与后端服务的交互和相互信任是核心。
I want to add CORS support to my server
Using CORS