Cross-Origin Resource Sharing?(CORS) is a mechanism that uses additional?HTTP?headers to tell browsers to give a web application running at one?origin, access to selected resources from a different origin.
它允許瀏覽器向跨源服務(wù)器發(fā)出XMLHttpRequest芜壁,從而克服了AJAX只能同源使用的限制袜蚕。CORS也已成為主流的跨域解決方案。
瀏覽器將CORS跨域請(qǐng)求分為簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求宽档,瀏覽器對(duì)這兩種的處理是不一樣的。
只要同時(shí)滿足兩個(gè)條件惜傲,就屬于簡(jiǎn)單請(qǐng)求:
(1)使用下列方法之一:
head/get/post
(2)請(qǐng)求的Heder是
Accept
Accept-Language
Content-Language
3)Content-Type只限于三個(gè)值:
application/x-www-form-urlencoded
multipart/form-data
text/plain
對(duì)于簡(jiǎn)單請(qǐng)求瀏覽器直接發(fā)出CORS請(qǐng)求,具體就是在頭信息之中增加一個(gè)Origin字段竟贯。
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
上面的頭信息中答捕,Origin字段用來(lái)說(shuō)明本次請(qǐng)求來(lái)自哪個(gè)源(協(xié)議 + 域名 + 端口),服務(wù)器根據(jù)這個(gè)值決定是否同意這次請(qǐng)求屑那。
CORS請(qǐng)求設(shè)置的響應(yīng)頭字段拱镐,都以 Access-Control-開(kāi)頭:
1)Access-Control-Allow-Origin:必選
它的值要么是請(qǐng)求時(shí)Origin字段的值,要么是一個(gè)*持际,表示接受任意域名的請(qǐng)求沃琅。
2)Access-Control-Allow-Credentials:可選
它的值是一個(gè)布爾值,表示是否允許發(fā)送Cookie蜘欲。默認(rèn)情況下Cookie不包括在CORS請(qǐng)求之中益眉,設(shè)為true即表示服務(wù)器明確許可,Cookie可以包含在請(qǐng)求中一起發(fā)給服務(wù)器。這個(gè)值也只能設(shè)為true郭脂,如果服務(wù)器不要瀏覽器發(fā)送Cookie年碘,刪除該字段即可。
需注意的是:由于同源策略的限制展鸡,所讀取的cookie為跨域請(qǐng)求接口所在域的cookie屿衅,而非當(dāng)前頁(yè)。
3)Access-Control-Expose-Headers:可選
CORS請(qǐng)求時(shí)娱颊,XMLHttpRequest對(duì)象的getResponseHeader()方法只能拿到6個(gè)基本字段:Cache-Control傲诵、Content-Language、Content-Type箱硕、Expires拴竹、Last-Modified、Pragma剧罩。如果想拿到其他字段栓拜,就必須在Access-Control-Expose-Headers里面指定。上面例子指定惠昔,getResponseHeader('FooBar')可以返回FooBar字段的值幕与。
非簡(jiǎn)單請(qǐng)求是那種對(duì)服務(wù)器有特殊要求的請(qǐng)求,比如請(qǐng)求方法是PUT或DELETE镇防,或者Content-Type字段的類型是application/json啦鸣。非簡(jiǎn)單請(qǐng)求的CORS請(qǐng)求,會(huì)在正式通信之前来氧,增加一次HTTP查詢請(qǐng)求诫给,稱為"預(yù)檢"請(qǐng)求(preflight)。
預(yù)檢請(qǐng)求用的請(qǐng)求方法是OPTIONS啦扬,表示這個(gè)請(qǐng)求是用來(lái)詢問(wèn)的中狂。請(qǐng)求頭信息里面,關(guān)鍵字段是Origin扑毡,表示請(qǐng)求來(lái)自哪個(gè)源胃榕。除了Origin字段,預(yù)檢請(qǐng)求的頭信息包括兩個(gè)特殊字段瞄摊。
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0..
1)Access-Control-Request-Method:必選
用來(lái)列出瀏覽器的CORS請(qǐng)求會(huì)用到哪些HTTP方法勋又,上例是PUT。
2)Access-Control-Request-Headers:可選
該字段是一個(gè)逗號(hào)分隔的字符串换帜,指定瀏覽器CORS請(qǐng)求會(huì)額外發(fā)送的頭信息字段楔壤,上例是X-Custom-Header。
服務(wù)器收到預(yù)檢請(qǐng)求膜赃,檢查了Origin挺邀、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,確認(rèn)允許跨源請(qǐng)求,就可以做出回應(yīng)端铛。
HTTP回應(yīng)中泣矛,除了關(guān)鍵的是Access-Control-Allow-Origin字段,其他CORS相關(guān)字段如下:
1)Access-Control-Allow-Methods:必選
它的值是逗號(hào)分隔的一個(gè)字符串禾蚕,表明服務(wù)器支持的所有跨域請(qǐng)求的方法您朽。注意,返回的是所有支持的方法换淆,而不單是瀏覽器請(qǐng)求的那個(gè)方法哗总,這是為了避免多次預(yù)檢請(qǐng)求。
2)Access-Control-Allow-Headers
如果瀏覽器請(qǐng)求包括Access-Control-Request-Headers字段倍试,則Access-Control-Allow-Headers字段是必需的讯屈。它也是一個(gè)逗號(hào)分隔的字符串,表明服務(wù)器支持的所有頭信息字段县习,不限于瀏覽器在預(yù)檢中請(qǐng)求的字段涮母。
3)Access-Control-Allow-Credentials:可選
該字段與簡(jiǎn)單請(qǐng)求時(shí)的含義相同。
4)Access-Control-Max-Age:可選
用來(lái)指定本次預(yù)檢請(qǐng)求的有效期躁愿,單位為秒叛本。
普通跨域請(qǐng)求只服務(wù)端設(shè)置Access-Control-Allow-Origin即可,前端無(wú)須設(shè)置彤钟。若要帶cookie請(qǐng)求来候,前后端都需要設(shè)置。
1逸雹、 前端設(shè)置:
1.)原生ajax
// 前端設(shè)置是否帶cookie
xhr.withCredentials =true;
示例代碼:
var xhr = new XMLHttpRequest();?
// 前端設(shè)置是否帶cookie
xhr.withCredentials =true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
? ? if (xhr.readyState == 4 && xhr.status == 200) {
? ? ? ? alert(xhr.responseText);
? ? }
};
2.)jQuery ajax
$.ajax({
? ? ...
? ?xhrFields: {
? ? ? ?withCredentials: true? ? // 前端設(shè)置是否帶cookie
? ?},
? ?crossDomain: true,? // 會(huì)讓請(qǐng)求頭中包含跨域的額外信息营搅,但不會(huì)含cookie
? ? ...
});
3.)vue框架
a.) axios設(shè)置:
axios.defaults.withCredentials =?true
b.) vue-resource設(shè)置:
Vue.http.options.credentials =?true
2、 服務(wù)端設(shè)置:
若后端設(shè)置成功峡眶,前端瀏覽器控制臺(tái)則不會(huì)出現(xiàn)跨域報(bào)錯(cuò)信息剧防,反之植锉,說(shuō)明沒(méi)設(shè)成功辫樱。
1.)Java后臺(tái):
/*
* 導(dǎo)入包:import javax.servlet.http.HttpServletResponse;
* 接口參數(shù)中定義:HttpServletResponse response
*/
// 允許跨域訪問(wèn)的域名:若有端口需寫全(協(xié)議+域名+端口),若沒(méi)有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允許前端帶認(rèn)證cookie:?jiǎn)⒂么隧?xiàng)后俊庇,上面的域名不能為'*'狮暑,必須指定具體的域名,否則瀏覽器會(huì)提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS預(yù)檢時(shí)辉饱,后端需要設(shè)置的兩個(gè)常用自定義頭
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
2.)Nodejs后臺(tái)示例:
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
? ? var postData = '';
? ? // 數(shù)據(jù)塊接收中
? ? req.addListener('data', function(chunk) {
? ? ? ? postData += chunk;
? ? });
? ? // 數(shù)據(jù)接收完畢
? ? req.addListener('end', function() {
? ? ? ? postData = qs.parse(postData);
? ? ? ? // 跨域后臺(tái)設(shè)置
? ? ? ? res.writeHead(200, {
? ? ? ? ? ? 'Access-Control-Allow-Credentials': 'true',? ? // 后端允許發(fā)送Cookie
? ? ? ? ? ? 'Access-Control-Allow-Origin': 'http://www.domain1.com',? ? // 允許訪問(wèn)的域(協(xié)議+域名+端口)
? ? ? ? ? ? /*
? ? ? ? ? ? * 此處設(shè)置的cookie還是domain2的而非domain1搬男,因?yàn)楹蠖艘膊荒芸缬驅(qū)慶ookie(nginx反向代理可以實(shí)現(xiàn)),
? ? ? ? ? ? * 但只要domain2中寫入一次cookie認(rèn)證彭沼,后面的跨域接口都能從domain2中獲取cookie缔逛,從而實(shí)現(xiàn)所有的接口都能跨域訪問(wèn)
? ? ? ? ? ? */
? ? ? ? ? ? 'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'? // HttpOnly的作用是讓js無(wú)法讀取cookie
? ? ? ? });
? ? ? ? res.write(JSON.stringify(postData));
? ? ? ? res.end();
? ? });
});
server.listen('8080');
console.log('Server is running at port 8080...');
cors要允許*.qq.com訪問(wèn)怎么設(shè)置?有一個(gè)a.qq.com的圖片發(fā)到百度貼吧上,會(huì)不會(huì)帶上那個(gè)cookie褐奴?
能說(shuō)說(shuō)同源策略嗎按脚,那如果是直接請(qǐng)求ip會(huì)有同源策略嗎,如果一個(gè)域名對(duì)應(yīng)多個(gè)ip的情況呢敦冬?