Vue中應用CORS實現AJAX跨域,及它在 form data 和 request payload 的小坑處理


基本概念部分(一):理解CORS

說道Vue的跨域AJAX,我想先梳理一遍CORS跨域,"跨域資源共享"(Cross-origin resource sharing),它是一個W3C標准。

CORS跨域的特點:它需要服務器的‘配合’。就是說,它的實現是:瀏覽器(所有瀏覽器和IE10+)+服務器

一般情況下,我們可以在請求頭信息中加入Origin,來告知服務器自己來自哪個源:協議 + 域名 + 端口。如果Origin域名在指定許可范圍內,則服務器的響應頭會多出三個信息:

Access-Control-Allow-Origin:
//它的值,可以使一個 *,表示接受所有域名的請求;還可以是指定的一個域名(在請求時就已經寫好的那個origin域名)。
Access-Control-Allow-Credentials:
//它的值為:true。他表示是否允許發送cookie,因為cookie不包含在CORS中,只有其值設為true時,可以讓Cookie包含在請求中一起發給服務器。
Access-Control-Expose-Headers:
//他表示XMLHttpRequest對象的getResponseHeader()方法的六個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。(這里我用的最多的是Content-Type)

這里有一個withCredentials屬性需要我們知道。

因為CORS請求默認不發送Cookie和HTTP認證信息,因此需要 Access-Control-Allow-Credentials:true; 並且專門設置AJAX請求:(這里在Vue中有應用,下面會說)

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

這樣才可以讓瀏覽器同意發送Cookie,配合服務器的需求和配置。

CORS還有一種情況是發送“預檢請求”。他會在正真的數據請求之前,先發送一次HTTP請求。瀏覽器會先詢問服務器自己的域名是否被許可,以及一些必要的頭部字段信息。服務器進行回復后,瀏覽器再發送一次,這次是正式的 XMLHttpRequest 請求。

這里面說到的“預檢”請求的方法為options方法,表示說:“我是來詢問的”。因此當我們在Chrome的開發者工具中會看到這個一串請求行:

OPTIONS /cors HTTP/1.1

對於這一點的應用我的項目中主要是當 Content-Type 為 application/json的時候,其他的put或者delete也會有這樣的請求方式。

總的來說只是一個對CORS的梳理,並沒有很細致的解釋。它與JSONP的不同為JSONP只有get請求可以跨域,而CORS支持所有的請求方式。雖然JSONP對老的瀏覽器支持比較好,但現在開發項目的瀏覽器大多較新,我也就更多的關注了CORS。

基本概念部分(二):理解 form data 和 request payload

在W3C中,<form>標簽的enctype屬性規定了表單信息在發送到服務器之前,應該如何對數據進行編碼。而且編碼的格式由它的三個屬性值決定:

application/x-www-form-urlencoded //在發送前編碼所有字符(默認)
multipart/form-data //不對字符編碼。在使用包含文件上傳控件的表單時,必須使用該值。
text/plain //空格轉換為 "+" 加號,但不對特殊字符編碼。

在普通的HTTP POST請求中,Content-Type 為 application/x-www-form-urlencoded,參數是在請求體中。即在請求的Form Data中。

而如果使用原生的AJAX POST請求,請求的 Content-Type 為 text/plain;charset=UTF-8 ,並且請求的參數在Request Payload中。

因此:在使用原生的AJAX POST請求時,要明確設置請求頭的Content-Type屬性值。(其實我很想知道如果我就放在Request Payload中,服務器是拿不到數據嗎?)

在我開發過程中響應頭headers中的Content-Type較為常用的有三個值(其實常用的不只有這三個):

1.application/x-www-form-urlencoded:這個值是form表單的默認屬性的屬性值,而且JQuery的AJAX的Content-Type默認值也是這個。

2.multipart/form-data:在使用表單上傳文件的時候,enctype一定要用到這個屬性值。詳細的請問度娘。

3.application/ json:這個值我經常用到,因為我們的后台工程師需要我傳JSON給他。這個屬性值告訴服務器,此次請求的消息主體是JSON的格式。此前在AngularJs項目中也有見過,它的AJAX請求默認的就是JSON字符串。並且JSON 格式支持比鍵值對復雜得多的結構化數據(那種層級很深的想想都蛋疼)。

 

   本文原文出自MINGXINICE的博客:http://www.cnblogs.com/mingxinice/p/vue-ajax-cors.html

正題:Vue中應用CORS實現AJAX跨域

ok終於把基礎知識梳理完了,下面我就要開始說Vue中對CORS的應用,以及它如何設置它的參數放在哪里了。

在Vue中想實現與后台的數據交互,缺少不了vue-resource模塊。就像jQuery里的$.ajax,用來和后端交互數據的。

正是vue-resource應用到了W3C中的新特性CORS。目前大部分的瀏覽器都已經支持 XMLHttpRequest2 對象用於在后台與服務器交換數據。

但是在Vue中提交AJAX跨域請求時,我們人需要知道當前瀏覽器是否支持 XMLHttpRequest2。判斷的方法是使用in操作檢測當前XMLHttpRequest示例對象是否包含withCredentials屬性,如果包含則支持CORS(因為withCredentials屬性是XMLHttpRequest對象獨有的,且如上文說,它是跨域傳輸Cookie和HTTP認證信息的關鍵)。

var xhrCors = 'withCredentials' in new XMLHttpRequest()

在支持CORS的情況下,還需要服務器啟用CORS支持。

如果我們想從http://example.com域中提交請求到http://crossdimain.com域,那么需要在crossdomain.com域中添加如下請求頭:

Access-Control-Allow-Origin : http://example.com

如果crossdomian.com要允許所有異域都可以AJAX請求該域資源,則添加如下響應頭:

Access-Control-Allow-Origin : *

這樣服務器開啟CORS支持后,在瀏覽器中就可以像提交普通的AJAX請求一樣,提交跨域請求了。

而真正知道這些后,在應用到開發環境中還會發現一個小坑:這個$http請求並不像jquery的ajax一樣,這里的post的data默認不是以form data的形式,而是request payload。(根據上述研究,可以判斷Vue的AJAX請求,很可能是以原生的方式,這里小生純屬猜測)

在學習了上述的基礎知識后,才發現這個小坑很好解決。我們只需要把請求頭的 Content-Type 值設置為 application/x-www-form-urlencoded 即可。我的項目代碼如下:

this.$http.post(                
  'https://zmx.mxorz.com/user/userCenter', {
     usertId: usertId
   }, {
       'headers': {
           'Content-Type': 'application/x-www-form-urlencoded'
       }
   }
).then(function(res) {                
}, function(res) {
})    

但是還有一種方法,是直接設置 emulateJSON 屬性為 true。感覺這個放方法的易用性更強。我的項目代碼如下:

this.$http.post(                
  'https://zmx.mxorz.com/user/userCenter', {
     usertId: usertId
   }, {
      emulateJSON:true
   }, {
       'headers': {
           'Content-Type': 'application/json'
       }
   }
).then(function(res) {                
}, function(res) {
})

  具體的梳理只有這么多,對Vue的各方面理解並不是很細致,望各位大佬多多提點~

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM