《Nginx通過CORS實(shí)現(xiàn)跨域》要點(diǎn):
本文介紹了Nginx通過CORS實(shí)現(xiàn)跨域,希望對(duì)您有用。如果有疑問,可以聯(lián)系我們。
CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱是跨域資源共享(Cross-origin resource sharing).它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請(qǐng)求,從而克服了AJAX只能同源使用的限制.
當(dāng)前幾乎所有的瀏覽器(Internet Explorer 8+, Firefox 3.5+, Safari 4+和 Chrome 3+)都可通過名為跨域資源共享(Cross-Origin Resource Sharing)的協(xié)議支持AJAX跨域調(diào)用.
Chrome,Firefox,Opera,Safari都使用的是XMLHttpRequest2對(duì)象,IE使用XDomainRequest.
簡單來說就是跨域的目標(biāo)服務(wù)器要返回一系列的Headers,通過這些Headers來控制是否同意跨域.跨域資源共享(CORS)也是未來的跨域問題的標(biāo)準(zhǔn)解決方案.
CORS提供如下Headers,Request包和Response包中都有一部分.
其中最敏感的就是Access-Control-Allow-Origin這個(gè)Header, 它是W3C標(biāo)準(zhǔn)里用來檢查該跨域請(qǐng)求是否可以被通過.(Access Control Check).如果需要跨域,解決方法就是在資源的頭中加入Access-Control-Allow-Origin 指定你授權(quán)的域.
假設(shè)您的應(yīng)用已經(jīng)在example.com上了,而您想要從www.example2.com提取數(shù)據(jù).一般情況下,如果您嘗試進(jìn)行這種類型的AJAX調(diào)用,請(qǐng)求將會(huì)失敗,而瀏覽器將會(huì)出現(xiàn)源不匹配的錯(cuò)誤.利用CORS后只需www.example2.com 服務(wù)端添加一個(gè)HTTP Response頭,就可以允許來自example.com的請(qǐng)求.
將Access-Control-Allow-Origin添加到某網(wǎng)站下或整個(gè)域中的單個(gè)資源
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Credentials: true (可選)
將允許任何域向您提交請(qǐng)求
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true (可選)
如果服務(wù)器端已啟用了CORS,那么提交跨域請(qǐng)求就和普通的XMLHttpRequest請(qǐng)求沒什么區(qū)別.例如現(xiàn)在example.com可以向www.example2.com提交請(qǐng)求.
var xhr = new XMLHttpRequest();
// xhr.withCredentials = true; //如果需要Cookie等
xhr.open('GET', 'http://www.example2.com/hello.json');
xhr.onload = function(e) {
?var data = JSON.parse(this.response);
?...
}
xhr.send();
要實(shí)現(xiàn)CORS跨域,服務(wù)端需要下圖中這樣一個(gè)流程
流程如下
用偽代碼表示
location /pub/(.+) {
? ?if ($http_origin ~ <允許的域(正則匹配)>) {
? ? ? ?add_header 'Access-Control-Allow-Origin' "$http_origin";
? ? ? ?add_header 'Access-Control-Allow-Credentials' "true";
? ? ? ?if ($request_method = "OPTIONS") {
? ? ? ? ? ?add_header 'Access-Control-Max-Age' 86400;
? ? ? ? ? ?add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE';
? ? ? ? ? ?add_header 'Access-Control-Allow-Headers' 'reqid, nid, host, x-real-ip, x-forwarded-ip, event-type, event-id, accept, content-type';
? ? ? ? ? ?add_header 'Content-Length' 0;
? ? ? ? ? ?add_header 'Content-Type' 'text/plain, charset=utf-8';
? ? ? ? ? ?return 204;
? ? ? ?}
? ?}
? ?# 正常nginx配置
? ?......
}
在nginx.conf里找到server項(xiàng),并在里面添加如下配置
location /{
add_header 'Access-Control-Allow-Origin' 'http://example.com';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Requested-With';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
...
}
如果需要允許來自任何域的訪問,可以這樣配置
add_header Access-Control-Allow-Origin *;
注釋如下
第一條指令:授權(quán)從example.com的請(qǐng)求(必需)
第二條指令:當(dāng)該標(biāo)志為真時(shí),響應(yīng)于該請(qǐng)求是否可以被暴露(可選)
第三條指令:允許腳本訪問的返回頭(可選)
第四條指令:指定請(qǐng)求的方法,可以是GET, POST, OPTIONS, PUT, DELETE等(可選)
重啟Nginx
$ service nginx reload
測試跨域請(qǐng)求
$ curl -I -X OPTIONS -H "Origin: http://example.com" http://www.example2.com
成功時(shí),響應(yīng)頭是如下所示
HTTP/1.1 200 OK
Server: nginx
Access-Control-Allow-Origin: example.com
由于Access-Control-Allow-Origin參數(shù)只允許配置單個(gè)域名或者*
,當(dāng)我們需要允許多個(gè)域名跨域訪問時(shí)可以用以下幾種方法來實(shí)現(xiàn).
如需要允許用戶請(qǐng)求來自www.example.com、m.example.com、wap.example.com訪問www.example2.com域名時(shí),返回頭Access-Control-Allow-Origin,具體配置如下
在nginx.conf里面,找到server項(xiàng),并在里面添加如下配置
map $http_origin $corsHost {
? ?default 0;
? ?"~http://www.example.com" http://www.example.com;
? ?"~http://m.example.com" http://m.example.com;
? ?"~http://wap.example.com" http://wap.example.com;
}
server
{
? ?listen 80;
? ?server_name www.example2.com;
? ?root /usr/share/nginx/html;
? ?location /
? ?{
? ? ? ?add_header Access-Control-Allow-Origin $corsHost;
? ?}
}
如需要允許用戶請(qǐng)求來自localhost、www.example.com或m.example.com的請(qǐng)求訪問xxx.example2.com域名時(shí),返回頭Access-Control-Allow-Origin,具體配置如下
在Nginx配置文件中xxx.example2.com域名的location /下配置以下內(nèi)容
set $cors '';
if ($http_origin ~* 'https?://(localhost|www\.example\.com|m\.example\.com)') {
? ? ? ?set $cors 'true';
}
if ($cors = 'true') {
? ? ? ?add_header 'Access-Control-Allow-Origin' "$http_origin";
? ? ? ?add_header 'Access-Control-Allow-Credentials' 'true';
? ? ? ?add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
? ? ? ?add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With';
}
if ($request_method = 'OPTIONS') {
? ? ? ?return 204;
}
如需要允許用戶請(qǐng)求來自*.example.com訪問xxx.example2.com域名時(shí),返回頭Access-Control-Allow-Origin,具體配置如下
在Nginx配置文件中xxx.example2.com域名的location /下配置以下內(nèi)容
if ( $http_origin ~ http://(.*).example.com){
? ? ? ? set $allow_url $http_origin;
? ?}
? ?#CORS(Cross Orign Resource-Sharing)跨域控制配置
? ?#是否允許請(qǐng)求帶有驗(yàn)證信息
? ?add_header Access-Control-Allow-Credentials true;
? ?#允許跨域訪問的域名,可以是一個(gè)域的列表,也可以是通配符*
? ?add_header Access-Control-Allow-Origin $allow_url;
? ?#允許腳本訪問的返回頭
? ?add_header Access-Control-Allow-Headers 'x-requested-with,content-type,Cache-Control,Pragma,Date,x-timestamp';
? ?#允許使用的請(qǐng)求方法,以逗號(hào)隔開
? ?add_header Access-Control-Allow-Methods 'POST,GET,OPTIONS,PUT,DELETE';
? ?#允許自定義的頭部,以逗號(hào)隔開,大小寫不敏感
? ?add_header Access-Control-Expose-Headers 'WWW-Authenticate,Server-Authorization';
? ?#P3P支持跨域cookie操作
? ?add_header P3P 'policyref="/w3c/p3p.xml", CP="NOI DSP PSAa OUR BUS IND ONL UNI COM NAV INT LOC"';
如需要允許用戶請(qǐng)求來自xxx1.example.com或xxx1.example1.com訪問xxx.example2.com域名時(shí),返回頭Access-Control-Allow-Origin,具體配置如下
在Nginx配置文件中xxx.example2.com域名的location /下配置以下內(nèi)容
location / {
? ?if ( $http_origin ~ .*.(example|example1).com ) {
? ?add_header Access-Control-Allow-Origin $http_origin;
? ?}
}
默認(rèn)Access-Control-Allow-Origin開啟跨域請(qǐng)求只支持GET、HEAD、POST、OPTIONS請(qǐng)求,使用DELETE發(fā)起跨域請(qǐng)求時(shí),瀏覽器出于安全考慮會(huì)先發(fā)起OPTIONS請(qǐng)求,服務(wù)器端接收到的請(qǐng)求方式就變成了OPTIONS,所以引起了服務(wù)器的405 Method Not Allowed.
解決方法
首先要對(duì)OPTIONS請(qǐng)求進(jìn)行處理
if ($request_method = 'OPTIONS') {
? ?add_header Access-Control-Allow-Origin *;
? ?add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
? ?#其他頭部信息配置,省略...
? ?return 204;
}
當(dāng)請(qǐng)求方式為OPTIONS時(shí)設(shè)置Allow的響應(yīng)頭,重新處理這次請(qǐng)求.這樣發(fā)出請(qǐng)求時(shí)第一次是OPTIONS請(qǐng)求,第二次才是DELETE請(qǐng)求.
# 完整配置參考
# 將配置文件的放到對(duì)應(yīng)的server {}里
add_header Access-Control-Allow-Origin *;
location / {
? ?if ($request_method = 'OPTIONS') {
? ? ? ?add_header Access-Control-Allow-Origin *;
? ? ? ?add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
? ? ? ?return 204;
? ?}
? ?index index.php;
? ?try_files $uri @rewriteapp;
}
The following Nginx configuration enables CORS, with support for preflight requests.
#
# Wide-open CORS config for nginx
#
location / {
? ? if ($request_method = 'OPTIONS') {
? ? ? ?add_header 'Access-Control-Allow-Origin' '*';
? ? ? ?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-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-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 = 'OPTIONS') { ?
? ?add_header 'Access-Control-Allow-Origin' 'https://docs.domain.com'; ?
? ?add_header 'Access-Control-Allow-Credentials' 'true'; ?
? ?add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS'; ?
? ?add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,token'; ?
? ?return 204;
}
if ($request_method = 'POST') { ?
? ?add_header 'Access-Control-Allow-Origin' 'https://docs.domain.com'; ?
? ?add_header 'Access-Control-Allow-Credentials' 'true'; ?
? ?add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS'; ?
? ?add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,token'; ?
} ?
if ($request_method = 'GET') { ?
? ?add_header 'Access-Control-Allow-Origin' 'https://docs.domain.com'; ?
? ?add_header 'Access-Control-Allow-Credentials' 'true'; ?
? ?add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS'; ?
? ?add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,token'; ?
}
在httpd配置或.htaccess文件中添加如下語句
SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1 ?
Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
通過在服務(wù)端設(shè)置Access-Control-Allow-Origin響應(yīng)頭
<?php
header("Access-Control-Allow-Origin: *");
?>
<?php
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
?>
由于瀏覽器實(shí)現(xiàn)只支持了單個(gè)origin、*、null,如果要配置多個(gè)訪問源,可以在代碼中處理如下
<?php
$allowed_origins ? = array( ?
? ? ? ? ? ? ? ? ? ? ? ? ? ?"http://www.example.com" ? , ?
? ? ? ? ? ? ? ? ? ? ? ? ? ?"http://app.example.com" ?, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ?"http://cms.example.com" ?, ?
? ? ? ? ? ? ? ? ? ? ? ? ?); ?
if (in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)){ ? ?
? ?@header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']); ?
}
?>
<meta http-equiv="Access-Control-Allow-Origin" content="*">
http://t.cn/RZEYPmD
http://t.cn/RhcAN2d
http://to-u.xyz/2016/06/30/nginx-cors/
http://coderq.github.io/2016/05/13/cross-domain/
作者:Mike
文章出處:運(yùn)維之美
Nginx與httpd對(duì)比
nginx 利用 proxy 反向代理解決 Ajax 跨域訪問,瀏覽器不顯示跳轉(zhuǎn)后的鏈接
轉(zhuǎn)載請(qǐng)注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/4429.html