若是前端有nginx方向代理,跨域配置在前端反向代理nginx上php
要作跨域域名限制html
CORS是一個W3C標準,全稱是跨域資源共享(Cross-origin resource sharing)。它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。前端
當前幾乎全部的瀏覽器(Internet Explorer 8+, Firefox 3.5+, Safari 4+和 Chrome 3+)均可經過名爲跨域資源共享(Cross-Origin Resource Sharing)的協議支持AJAX跨域調用。nginx
Chrome,Firefox,Opera,Safari都使用的是XMLHttpRequest2對象,IE使用XDomainRequest。git
簡單來講就是跨域的目標服務器要返回一系列的Headers,經過這些Headers來控制是否贊成跨域。跨域資源共享(CORS)也是將來的跨域問題的標準解決方案。github
CORS提供以下Headers,Request包和Response包中都有一部分。json
其中最敏感的就是Access-Control-Allow-Origin這個Header, 它是W3C標準裏用來檢查該跨域請求是否能夠被經過。(Access Control Check)。若是須要跨域,解決方法就是在資源的頭中加入Access-Control-Allow-Origin 指定你受權的域。跨域
假設您的應用已經在example.com上了,而您想要從www.example2.com提取數據。通常狀況下,若是您嘗試進行這種類型的AJAX調用,請求將會失敗,而瀏覽器將會出現源不匹配的錯誤。利用CORS後只需www.example2.com 服務端添加一個HTTP Response頭,就能夠容許來自example.com的請求。瀏覽器
將Access-Control-Allow-Origin添加到某網站下或整個域中的單個資源安全
Access-Control-Allow-Origin: http://example.com Access-Control-Allow-Credentials: true (可選)
將容許任何域向您提交請求
Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true (可選)
若是服務器端已啓用了CORS,那麼提交跨域請求就和普通的XMLHttpRequest請求沒什麼區別。例如如今example.com能夠向www.example2.com提交請求。
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();
要實現CORS跨域,服務端須要下圖中這樣一個流程
流程以下
用僞代碼表示
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項,並在裏面添加以下配置
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 *;
註釋以下
第一條指令:受權從example.com的請求(必需)
第二條指令:當該標誌爲真時,響應於該請求是否能夠被暴露(可選)
第三條指令:容許腳本訪問的返回頭(可選)
第四條指令:指定請求的方法,能夠是GET, POST, OPTIONS, PUT, DELETE等(可選)
重啓Nginx
$ service nginx reload
測試跨域請求
$ curl -I -X OPTIONS -H "Origin: http://example.com" http://www.example2.com
成功時,響應頭是以下所示
HTTP/1.1 200 OK Server: nginx Access-Control-Allow-Origin: example.com
因爲Access-Control-Allow-Origin參數只容許配置單個域名或者*
,當咱們須要容許多個域名跨域訪問時能夠用如下幾種方法來實現。
如須要容許用戶請求來自www.example.com、m.example.com、wap.example.com訪問www.example2.com域名時,返回頭Access-Control-Allow-Origin,具體配置以下
在nginx.conf裏面,找到server項,並在裏面添加以下配置
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; } }
如須要容許用戶請求來自localhost、www.example.com或m.example.com的請求訪問xxx.example2.com域名時,返回頭Access-Control-Allow-Origin,具體配置以下
在Nginx配置文件中xxx.example2.com域名的location /下配置如下內容
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; }
如須要容許用戶請求來自*.example.com訪問xxx.example2.com域名時,返回頭Access-Control-Allow-Origin,具體配置以下
在Nginx配置文件中xxx.example2.com域名的location /下配置如下內容
if ( $http_origin ~ http://(.*).example.com){ set $allow_url $http_origin; } #CORS(Cross Orign Resource-Sharing)跨域控制配置 #是否容許請求帶有驗證信息 add_header Access-Control-Allow-Credentials true; #容許跨域訪問的域名,能夠是一個域的列表,也能夠是通配符* 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'; #容許使用的請求方法,以逗號隔開 add_header Access-Control-Allow-Methods 'POST,GET,OPTIONS,PUT,DELETE'; #容許自定義的頭部,以逗號隔開,大小寫不敏感 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"';
如須要容許用戶請求來自xxx1.example.com或xxx1.example1.com訪問xxx.example2.com域名時,返回頭Access-Control-Allow-Origin,具體配置以下
在Nginx配置文件中xxx.example2.com域名的location /下配置如下內容
location / { if ( $http_origin ~ .*.(example|example1).com ) { add_header Access-Control-Allow-Origin $http_origin; } }
默認Access-Control-Allow-Origin開啓跨域請求只支持GET、HEAD、POST、OPTIONS請求,使用DELETE發起跨域請求時,瀏覽器出於安全考慮會先發起OPTIONS請求,服務器端接收到的請求方式就變成了OPTIONS,因此引發了服務器的405 Method Not Allowed。
解決方法
首先要對OPTIONS請求進行處理
if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS; #其餘頭部信息配置,省略... return 204; }
當請求方式爲OPTIONS時設置Allow的響應頭,從新處理此次請求。這樣發出請求時第一次是OPTIONS請求,第二次纔是DELETE請求。
# 完整配置參考 # 將配置文件的放到對應的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
經過在服務端設置Access-Control-Allow-Origin響應頭
<?php header("Access-Control-Allow-Origin: *"); ?>
<?php header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']); ?>
因爲瀏覽器實現只支持了單個origin、*、null,若是要配置多個訪問源,能夠在代碼中處理以下
<?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/