前端CORS請求梳理

先後端分離來講,跨域請求是咱們第一個須要解決的問題。下面是我在開發中總結出來的一些經驗。
javascript

開發中,不少時候會出現Options請求CORS預檢請求),可是有的時候又不會出現。某些請求不會觸發 CORS 預檢請求,這樣的請求被稱爲簡單請求,其餘的請求被稱爲非簡單請求。首先咱們來區分簡單請求和非簡單請求。css

1、簡單請求和非簡單請求

瀏覽器將CORS請求分紅兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。
只要同時知足如下兩大條件,就屬於簡單請求。html

一、請求方法是如下三種方法之一:

HEADGETPOST前端

二、HTTP的頭信息不超出如下幾種字段:

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限於三個值application/x-www-form-urlencodedmultipart/form-datatext/plain
凡是不一樣時知足上面兩個條件,就屬於非簡單請求。瀏覽器對這兩種請求的處理,是不同的。java

2、和跨域有關的頭部梳理

如今咱們知道咱們哪些請求是簡單請求哪些是非簡單請求,上面有提到HTTP頭部和CORS跨域請求,CORS全稱Cross-origin resource sharing,也就是跨域資源共享,瀏覽器出於安全角度考慮限制跨域HTTP請求,這就是同源策略,因此後端須要設置請求頭部才能容許跨域。node

一、Access-Control-Allow-Methods:

是逗號分隔的一個字符串,代表服務器容許的跨域請求的方法jquery

二、Access-Control-Allow-Headers:

是一個逗號分隔的字符串,代表服務器支持的全部頭信息字段,不限於瀏覽器在」預檢」中請求的字段。ajax

三、Access-Control-Allow-Credentials:

該字段表示是否能夠將對請求的響應暴露給頁面,通常來講是cookieCredentials必須在先後端都被配置才能使帶credentials的CORS請求成功jQuery能夠經過設置xhrFields: {withCredentials:true}promise能夠經過設置credentials: 'include'json

四、Access-Control-Max-Age:

用來指定本次預檢請求的有效期,單位爲秒。segmentfault

五、Access-Control-Allow-Origin:

表示資源是否被容許與給定的origin共享

六、Access-Control-Expose-Headers:

響應首部 Access-Control-Expose-Headers 列出了哪些首部能夠做爲響應的一部分暴露給外部。默認狀況下,只有六種 simple response headers (簡單響應首部)能夠暴露給外部:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。若是想要讓客戶端能夠訪問到其餘的首部信息,能夠將它們在 Access-Control-Expose-Headers 裏面列出來。

七、Access-Control-Request-Headers:

請求首部 Access-Control-Request-Headers 出現於 preflight request (預檢請求)中,用於通知服務器在真正的請求中會採用哪些請求首部

八、Access-Control-Request-Method:

請求首部 Access-Control-Request-Method 出現於 preflight request (預檢請求)中,用於通知服務器在真正的請求中會採用哪一種 HTTP 方法。由於預檢請求所使用的方法老是 OPTIONS ,與實際請求所使用的方法不同,因此這個首部是必要的。

3、發送cookie

若是須要發送cookie,先後端都被配置,前端須要設置jQuery能夠經過設置xhrFields: {withCredentials:true},promise能夠經過設置credentials: 'include'
服務器端須要設置res.setHeader('Access-Control-Allow-Credentials', 'true');不然瀏覽器就會報錯:

Response to preflight request doesn’t pass access control check: The value of the ‘Access-Control-Allow-Credentials’ header in the response is ‘’ which must be ‘true’ when the request’s credentials mode is ‘include’.

須要注意的是,若是要發送Cookie,Access-Control-Allow-Origin就不能設爲星號,必須指定明確的、與請求網頁一致的域名。

同時,Cookie依然遵循同源政策,只有用服務器域名設置的Cookie纔會上傳,其餘域名的Cookie並不會上傳,且(跨源)原網頁代碼中的document.cookie也沒法讀取服務器域名下的Cookie。
這時候瀏覽器會報錯

The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘
‘ when the request’s credentials mode is ‘include’.

*咱們來看看node如何不使用如何插件和框架來解析cookie
,下面是代碼:

//解析cookie的函數

function parseCookies (request) {    
    let list = {},
    rc = request.headers.cookie;

    rc && rc.split(';').forEach(function( cookie ) {        
        let parts = cookie.split('=');
        list[parts.shift().trim()] = decodeURI(parts.join('='));
    });    
    return list;
}
http.createServer(function (request, response) {    
    //讀取cookie
    var cookies = parseCookies(request);
    //寫入cookie
    response.writeHead(200, {            
        'Set-Cookie': 'mycookie=test',            
        'Content-Type': 'text/plain'
    });
    response.end('Hello World\n');}).listen(8124);
})
複製代碼

4、Content-Type的值及其做用

對接後端的接口的時候,Content-Type的值是決定後端那邊怎麼去解析咱們的傳參的。Content-type經常使用幾個值:

1.text/html
2.text/plain
3.text/css
4.text/javascript
5.application/x-www-form-urlencoded
6.multipart/form-data
7.application/json
8.application/xml

前面幾個都很好理解,都是html,css,javascript的文件類型,後面四個是POST的發包方式

一、application/x-www-form-urlencoded

html中表單提交的默認格式,jquery ajax請求默認的content-type默認也是這種格式,而且jquery會把data:{foo1:」bar1」,foo2:」bar2」}數據轉換成key1=value1&key2=value2,能夠經過processData來關閉是否提早處理數據,數據格式是key1=value1&key2=value2形式。

下面是jquery作data預處理的代碼,默認processData爲true,因此若是data有值就會進入判斷就會把json格式轉化爲key1=value1&key2=value2的格式

if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
    cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
    
    // #9682: remove data so that it's not used in an eventual retry
    delete s.data;
}複製代碼

二、multipart/form-data

multipart/form-data用在發送文件的POST包。
這裏Content-Type告訴咱們,發包是以multipart/form-data格式來傳輸,另外,還有boundary用於分割數據。
當文件太長,HTTP沒法在一個包以內發送完畢,就須要分割數據,分割成一個一個chunk發送給服務端,
那麼—用於區分數據快,然後面的數據sqe6Nhq4gtMfHLOY 就是標示區分包做用。

------WebKitFormBoundarysqe6Nhq4gtMfHLOY
Content-Disposition: form-data; name:"UserWxCode"

123
------WebKitFormBoundarysqe6Nhq4gtMfHLOY
Content-Disposition: form-data; name="CodeType"

Public
------WebKitFormBoundarysqe6Nhq4gtMfHLOY--複製代碼

三、application/json

發送請求的時候須要JSON.stringify一下,HTTP通訊中並不存在所謂的json,而是將string轉成json罷了,也就是,application/json能夠將它理解爲text/plain,普通字符串

四、text/xml和application/xml

text/xml忽略xml文件頭中的關於編碼的設定(<?xml version=」1.0」 encoding=」UTF-8」?>),默認採用us-ascii編碼。 application/xml會依照xml文件頭中編碼的設定推薦使用application/xml

5、fetch和jquery Ajax設置Headers,cookies

//fetch設置Headers,cookies

//方式1
let myHeaders = new Headers({    
   'Content-Type': 'application/json; charset=UTF-8',    
   'token': 123
});

//方式2
headers: {    
   'Content-Type': 'application/json; charset=UTF-8',    
   'token': 123
}

//發送cookies:
credentials: 'include'

//jquery ajax設置Headers,cookies

//設置header方式一
headers: {
   UserName: 'zxplus',
   EncryptKey: '1111'
},

//方式二
beforeSend: function(request) {
    request.setRequestHeader("UserName", "zxplus");
},
//發送cookie
xhrFields: {
   withCredentials:true //支持附帶詳細信息
},複製代碼

參考

https://stackoverflow.com/questions/3393854/get-and-set-a-single-cookie-with-node-js-http-serverhttp://www.ruanyifeng.com/blog/2016/04/cors.htmlhttps://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORShttps://segmentfault.com/a/1190000006039533http://www.cnblogs.com/caoshiqing/p/6825608.htmlhttp://homeway.me/2015/07/19/understand-http-about-content-type/

相關文章
相關標籤/搜索