php跨域资源共享,CORS 跨域资源共享
CORS (Cross-Origin Resource Sharing) 跨域資源共享
為什么需要 CORS
首先,跨域指的是同一個(gè)域名下的資源,同時(shí)要注意域名與子域名,比如 developers.e.qq.com 和 developers.proxy.qq.com 不屬于同一個(gè)域,同樣屬于跨域訪問(wèn)
由于 同源策略,瀏覽器會(huì)限制腳本中發(fā)起的跨域請(qǐng)求,比如通過(guò) XMLHttpRequest 就不能發(fā)起的跨域請(qǐng)求
PS: 不是不能發(fā)跨域請(qǐng)求,而是跨域請(qǐng)求可以正常發(fā)起,只不過(guò)瀏覽器會(huì)攔截返回結(jié)果
雖然有一些 jsonp 這些請(qǐng)求方式,不過(guò)都只是利用了一些標(biāo)簽的可跨域性解決的,實(shí)質(zhì)上已經(jīng)不屬于 XMLHttpRequest 的范圍了
為了能開發(fā)出更強(qiáng)大、更豐富、更安全的 Web 應(yīng)用程序,能夠在不丟失安全的前提下,Web 應(yīng)用技術(shù)能越來(lái)越強(qiáng)大、越來(lái)越豐富。比如,可以使用 XMLHttpRequest 發(fā)起跨域 HTTP 請(qǐng)求,于是就產(chǎn)生了一種新的機(jī)制,即 跨域資源共享(Cross-Origin Resource Sharing (CORS))
這種機(jī)制讓 Web 應(yīng)用服務(wù)器能支持跨域訪問(wèn)控制,從而使得安全地進(jìn)行跨域數(shù)據(jù)傳輸成為可能
需要注意的是,瀏覽器必須能夠支持這種新的訪問(wèn)機(jī)制,包括請(qǐng)求頭和策略執(zhí)行。同樣,服務(wù)器端則需要解析這些新的請(qǐng)求頭,并按照策略返回相應(yīng)的響應(yīng)頭以及所請(qǐng)求的資源
在說(shuō) CORS 之前,我們先來(lái)弄清兩個(gè)概念,請(qǐng)求與預(yù)請(qǐng)求
請(qǐng)求就不用多說(shuō),就是正常的 HTTP 請(qǐng)求
預(yù)請(qǐng)求
首先,發(fā)送的請(qǐng)求要滿足以下條件
請(qǐng)求以 GET, HEAD 或者 POST 以外的方法發(fā)起請(qǐng)求
如果使用 POST 的話,請(qǐng)求的 Content-Type 必須是 application/x-www-form-urlencoded, multipart/form-data 或者 text/plain 以外的數(shù)據(jù)類型。比如,POST 發(fā)送的 Content-Type 為 application/xml 或者 text/xml
使用自定義請(qǐng)求頭(比如: X-TEST)
當(dāng)請(qǐng)求包含這幾種特征時(shí),該請(qǐng)求會(huì)先發(fā)出一個(gè) 預(yù)請(qǐng)求,以 OPTIONS 的方式對(duì)服務(wù)器先請(qǐng)求,當(dāng)保證滿足 CORS 約定的條件時(shí),才會(huì)發(fā)出正式的請(qǐng)求
簡(jiǎn)單來(lái)說(shuō),預(yù)請(qǐng)求 就是為了保證服務(wù)器能夠支持跨域訪問(wèn),保證整個(gè)過(guò)程的訪問(wèn)安全
CORS 請(qǐng)求過(guò)程
ok,接下來(lái)我們來(lái)說(shuō)如何通過(guò) CORS 進(jìn)行跨域訪問(wèn),這里我們用 jquery 的 $.ajax() 的方法請(qǐng)求
首先,我們通過(guò) 預(yù)請(qǐng)求 的方式來(lái)確定服務(wù)器是否支持跨域
$.ajax({
url: 'http://developers.proxy.e.qq.com/cors.php',
method: 'POST',
'Content-Type': 'application/json',
headers: {
'X-TEST': 'test',
},
success: function(data) {
console.log(data);
}
});
下面是 預(yù)請(qǐng)求 的請(qǐng)求頭信息和響應(yīng)頭信息
// request headers
OPTIONS /cors.php HTTP/1.1
Host: developers.proxy.e.qq.com
Connection: keep-alive
Cache-Control: max-age=0
Access-Control-Request-Method: POST
Origin: http://localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 > Safari/537.36
Access-Control-Request-Headers: accept, x-test
Accept: /
Referer: http://localhost/example/index.php
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
// response headers
HTTP/1.1 200 OK
Date: Fri, 19 Aug 2016 03:32:18 GMT
Server: Apache
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-TEST
Access-Control-Max-Age: 86400
Cache-Control: max-age=0
Expires: Fri, 19 Aug 2016 03:32:18 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 23
Connection: close
Content-Type: text/html
在這里我們可以看到,預(yù)請(qǐng)求 的請(qǐng)求頭信息中有 Access-Control-Request-Headers: accept, x-test 和 Access-Control-Request-Method: POST 這兩個(gè)頭信息
Access-Control-Request-Headers:頭信息會(huì)告訴服務(wù)器,正式請(qǐng)求將會(huì)攜帶 accept、x-test 兩個(gè)請(qǐng)求頭信息
Access-Control-Request-Method:頭信息則告訴服務(wù)器,正式請(qǐng)求將會(huì)以 POST 的方式發(fā)起
然后服務(wù)器的響應(yīng)頭信息里面
Access-Control-Allow-Headers : 告訴我們接受 X-TEST 這個(gè)自定義的 header 頭
Access-Control-Allow-Methods : 服務(wù)器接受的方法 POST, GET, OPTIONS
Access-Control-Allow-Origin : 允許跨域訪問(wèn)的域名列表,這里是 localhost
Access-Control-Max-Age : 本次 預(yù)請(qǐng)求 的響應(yīng)結(jié)果有效時(shí)間是多久,這里 86400 秒表示一天內(nèi),瀏覽器在處理針對(duì)該服務(wù)器的跨站請(qǐng)求,都可以無(wú)需再發(fā)送預(yù)請(qǐng)求
請(qǐng)求頭里面的信息會(huì)和響應(yīng)頭信息里面的內(nèi)容進(jìn)行核對(duì),如果條件都滿足的話,預(yù)請(qǐng)求完成
然后 預(yù)請(qǐng)求 結(jié)束,結(jié)果表明支持跨域訪問(wèn),并且現(xiàn)在的域名也在跨域訪問(wèn)的列表內(nèi),確認(rèn)信息后,接下來(lái)會(huì)進(jìn)行正式的請(qǐng)求
下面是正式請(qǐng)求的請(qǐng)求頭信息和響應(yīng)頭信息
// request headers
POST /cors.php HTTP/1.1
Host: developers.proxy.e.qq.com
Connection: keep-alive
Content-Length: 0
Cache-Control: max-age=0
Accept: /
X-TEST: test
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 > Safari/537.36
Origin: http://localhost
Referer: http://localhost/example/index.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
// response headers
HTTP/1.1 200 OK
Date: Fri, 19 Aug 2016 03:32:18 GMT
Server: Apache
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-TEST
Access-Control-Max-Age: 86400
Cache-Control: max-age=0
Expires: Fri, 19 Aug 2016 03:32:18 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 23
Connection: close
Content-Type: text/html
這樣就完成了一次 CORS 的跨域請(qǐng)求過(guò)程
注意:服務(wù)器端也要做響應(yīng)的配置,如下示例:
// PHP 為例
header('Access-Control-Allow-Origin: http://localhost');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: X-TEST');
header('Access-Control-Max-Age: 0');
攜帶 Cookies 的請(qǐng)求
需要再 xhr 里面設(shè)置 withCredentials: true
同時(shí)服務(wù)器上面要設(shè)置返回的響應(yīng)頭信息 Access-Control-Allow-Credentials: true,否則不會(huì)返回響應(yīng)結(jié)果以保證信息的安全
$.ajax({
url: 'http://developers.proxy.e.qq.com/cors.php',
method: 'POST',
'Content-Type': 'text/plain',
xhrFields: {
withCredentials: true,
},
headers: {
'X-TEST': 'test',
},
success: function(data) {
console.log(data);
}
});
對(duì)應(yīng)的,服務(wù)器上要加上:
// PHP 為例
header('Access-Control-Allow-Credentials: true');
下面我們來(lái)列舉整個(gè)過(guò)程涉及到的響應(yīng)頭信息和請(qǐng)求頭信息
HTTP 響應(yīng)頭
Access-Control-Expose-Headers : 允許訪問(wèn)服務(wù)器的頭信息的白名單
Access-Control-Allow-Origin : 允許跨域訪問(wèn)的域名白名單
Access-Control-Allow-Methods : 允許跨域訪問(wèn)的 Method
Access-Control-Allow-Headers : 跨域訪問(wèn)時(shí)可以使用的自定義的 HTTP 請(qǐng)求頭
Access-Control-Max-Age : 本次預(yù)請(qǐng)求結(jié)果的有效期,在這個(gè)時(shí)間內(nèi)不需要再次預(yù)請(qǐng)求
Access-Control-Allow-Credentials : 當(dāng)為 true 時(shí),表明本次請(qǐng)求是攜帶 Cookies 的請(qǐng)求
HTTP 請(qǐng)求頭
Origin : 發(fā)送請(qǐng)求或是預(yù)請(qǐng)求的域名
Access-Control-Request-Method : 在正式請(qǐng)求中會(huì)使用的 Method
Access-Control-Request-Headers : 在正式請(qǐng)求中會(huì)攜帶的頭信息
總結(jié)
以上是生活随笔為你收集整理的php跨域资源共享,CORS 跨域资源共享的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Windows Workflow Fou
- 下一篇: c#实现Stack