當AJAX碰上CORS

看到 error message 出現 CORS 的幾種情形

Haiyin Liao
Channel-HWAN
5 min readSep 3, 2019

--

身為一位前端網頁設計師,會遇到的錯誤訊息種類不會太多或是太複雜解決,其中最令我傷透腦筋應該非CORS莫屬,不但錯誤訊息又臭又長,看完也無從下手,是否該修改網站的設定檔或是怎麼做網頁的宣告,以下我們將一步步慢慢探討各種有可能遇到的情形。

以下從我實際遇到的一個例子來說起:
當我們提交表單想把表單資料存入資料庫的時候,我們會呼叫$.ajax();,其中有一個data參數,在這裡我們將要傳送到server的資料指派給它:

formData裡面裝了什麼東西呢?

$('form')在呼叫.serialize()後會得到一個集結了所有表單資料的字串,如同將整個表單的資料打包成一包,這樣比一個欄位一欄位呼叫.val()的方式來得容易多了。

The .serialize() method creates a text string in standard URL-encoded notation.

在呼叫.serialize()後,表單的資料會轉換成以key-value成對的形式,如此在傳送表單前對表單資料進行事先處理,之後在取得、使用某個欄位的資料便能很輕而易舉地做對應。

在input名稱(name屬性)為message和name的欄位中分別輸入”A cup of tea”和”Panda”。經過.serialize()得到的結果如下:

接著就是進入$.ajax()進重頭戲的部分。以下是完整呼叫$.ajax()的程式碼:

注意一下contentType這個參數,這是用來告訴 server 它即將接收到的資料是什麼類型。由於表單資料在呼叫.serialize()之後得到的字串,型態跟MIME的application/x-www-form-urlencoded相同,因此我們將contentType的值設為application/x-www-form-urlencoded

$.ajax()contentType在未指定的時候,預設值即為application/x-www-form-urlencoded

For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server.

如上所述,如果contentType的值設為application/x-www-form-urlencodedmultipart/form-datatext/plain三者之外的值,就會觸發瀏覽器發送一個Preflight Request(預檢請求)到server−即呼叫OPTIONSfunction,此為在發送真正的request前所做的確認動作,目的是去檢查請求方是否為安全、可信賴的網域。如果Preflight Request不被允許的話,真正的請求就不會被送出。我們可以從開發者工具中的Network面板中檢視:

小插曲
在執行$.ajax()時為了確保請求有得到正確的回應,使用console.log() 印出 Http response code,得到的是表示請求成功的代碼200,但同時error callback function也被觸發了,這是為什麼呢?原因就出在dataType屬性。

我們設定dataType是用來告訴接收請求的server端,將資料轉換成指定的資料型態,如果資料在轉換的過程產生了任何錯誤,都有可能導致error的觸發,此時可以試著將dataType先註解掉以釐清程式碼執行錯誤的原因。

此時將error callback function的第二個參數印出來可以馬上應證是資料在轉換上發生問題:parseerror

參考資料:
https://blog.techbridge.cc/2017/05/20/api-ajax-cors-and-jsonp/
https://kjj6198.github.io/2019/01/18/cors-and-cookie/
https://imququ.com/post/four-ways-to-post-data-in-http.html
https://stackoverflow.com/questions/6186770/ajax-request-returns-200-ok-but-an-error-event-is-fired-instead-of-success

--

--