前後端聯調之Form Data與Request Payload,你真的瞭解嗎?

前言

做過前後端聯調的小夥伴,可能有時會遇到一些問題。例如,我明明傳遞數據給後端了,後端爲什麼說沒收到呢?這時候可能就會就會有小夥伴陷入迷茫,本文從chrome-dev-tools(F12調試器)中看到的FormDataRequestBody,給小夥伴們提供一種可能的思路。也給小夥伴們提供一些問題的探究方法。

簡介

什麼是FormData?什麼是RequestPayload?不解釋,直接上圖:

Request Paload

Form Data

區別?

因爲這裏觸及了我的知識盲區,所以有了本文。這個答案是我在stackoverflow上得到的。首先還是貼問題,貼答案。

What's the difference between “Request Payload” vs “Form Data” as seen in Chrome dev tools Network tab。
中文翻譯:chrome開發者工具中的Request Payload與Form Data有什麼區別?

高票回答:

The Request Payload - or to be more precise: payload body of a HTTP Request - is the data normally send by a POST or PUT Request. It's the part after the headers and the CRLF of a HTTP Request.

A request with Content-Type: application/json may look like this:

POST /some-path HTTP/1.1
Content-Type: application/json

{ "foo" : "bar", "name" : "John" }

If you submit this per AJAX the browser simply shows you what it is submitting as payload body. That’s all it can do because it has no idea where the data is coming from.

If you submit a HTML-Form with method="POST" and Content-Type: application/x-www-form-urlencoded or Content-Type: multipart/form-data your request may look like this:

POST /some-path HTTP/1.1
Content-Type: application/x-www-form-urlencoded

foo=bar&name=John

In this case the form-data is the request payload. Here the Browser knows more: it knows that bar is the value of the input-field foo of the submitted form. And that’s what it is showing to you.

So, they differ in the Content-Type but not in the way data is submitted. In both cases the data is in the message-body. And Chrome distinguishes how the data is presented to you in the Developer Tools.

翻譯過來是說:
Request Payload更準確的說是http request的payload body。一般用在數據通過POST請求或者PUT請求。它是HTTP請求中空行的後面那部分。(PS:這裏涉及一個http常被問到的問題,http請求由哪幾部分組成,一般是請求行,請求頭,空行,請求體。payload body應該是對應請求體。)

一個請求伴隨着header設置爲Content-Type: application/json時候,看起來可能像這樣:

POST /some-path HTTP/1.1
Content-Type: application/json

{ "foo" : "bar", "name" : "John" }

如果你正常請求一個ajax。瀏覽器會簡單的將你提交的內容作爲payload展示出來,這就是它所能做的,因爲它不知道數據來自哪裏。

如果你提交了一個html表單並且配置上了method="post",並且設置了Content-Type: application/x-www-form-urlencoded或者Content-Type: multipart/form-data。那麼你的請求可能長這個樣:

POST /some-path HTTP/1.1
Content-Type: application/x-www-form-urlencoded

foo=bar&name=John

這裏的form-data就是request payload。在這裏,瀏覽器知道更多:它知道bar是提交表單的輸入字段foo的值。這就是它向你展示的。

所以區別就是,他們只是因爲Content-Type設置的不同,並不是數據提交方式的不同,這兩種提交都會將數據放在message-body中。但是chrome瀏覽器的開發者工具會根據這個ContentType區分顯示方式。

細節

好了,到這裏我們知道了,其實都是放到了payload中。那麼具體有什麼區別呢?爲什麼有時候後端拿不到值呢?這就不得不說對payload的解析方式了。我們以幾個chrome下的測試案例,來理一理這個邏輯。

傳統的Form表單提交

場景構造

<form action="/" method="POST">
    <input name="name" type="text">
    <input name="password" type="text">
    <button>提交</button>
</form>

如果我這裏點擊提交按鈕,就會觸發瀏覽器的提交功能,那結果是什麼樣呢?

clipboard.png

注意點

可以看到Content-Typeapplication/x-www-form-urlencoded
值得形式是以key1=value1&key2=value2的形式提交的。

傳統的ajax提交

場景構造

function submit2() {
    var xhr = new XMLHttpRequest();
    xhr.timeout = 3000;
    var obj = {a: 1, b: 2};
    xhr.open('POST', '/');
    xhr.send(obj);
}

首先我們構造一個簡單的函數,然後觸發它。通過chrome反饋來看:

傳統ajax提交

注意點

1.默認的Content-Typetext/plain
2.Request Payload會對非字符串做字符串轉換。
3.通過xhr.send(JSON.stringify(obj));可修正要發的內容

axios方式提交

場景構造

由於axios已經是vue、react的準標配請求方式了,所以這裏探究一下它。
首先我門看axios的文檔,當post提交時候可以傳遞什麼類型參數:

clipboard.png

注意這個類型,我們分別構造兩個場景。對應它。

function submit3() {
    var sence1 = 'name=123&val=456';
    var sence2 = {name: 123, val: 456};
    axios.post('/', sence1)
}

分別傳遞字符串與對象,提交post請求,然後觀察結果:

場景1——傳遞字符串時候的結果:
字符串提交場景

場景2——傳遞對象的結果:
對象提交場景

注意點

1.當我們傳遞字符串的時候,Content-Type自動轉爲xxx-form-xxx的形式。當爲對象的時候,自動轉化爲xxx/json
2.字符串的時候以key1=val1&key2=val2的形式體現,對象以JSON字符串形式體現。

總結

探索了這麼多種情況之後,那麼我們回顧一下:

Content-Type的差異

1.傳統的ajax請求時候,Content-Type默認爲"文本"類型。
2.傳統的form提交的時候,Content-Type默認爲"Form"類型。
3.axios傳遞字符串的時候,Content-Type默認爲"Form"類型。
4.axios傳遞對象的時候,Content-Type默認爲"JSON"類型

Content-Type的值,Form與非Form時,payload的區別。

1.都只支持字符串類型(以上探究的幾種情況)
2.Form需要傳遞的格式爲key1=value1&key2=value2,類似GET請求的QueryString格式

  1. 非Form一般爲JSON.stringify(formDataObject)形式

後端取不到值?

無論何種形式傳遞,後端解析表單信息的時候,會考慮Content-Type。如果是JSON字符串的話,後端解析payload的內容時候,肯定要用JSON.parse(str)去解析啦。如果是key1=value1&key2=value2的形式,則需要去分割字符串。

當然這些事情一般後端使用的框架會去處理,但是框架給後端提供取值接口有可能是不同的,所以前端的小夥伴在處理請求問題時,一定要跟後端小夥伴商量好,是用JSON還是FormData哈。

後記

本來只是小小的一個問題,仔細研究起來發現挺多細節。今天就花時間整理了一下,希望能給大家一些幫助。碼字不容易,如果感到這篇文章對你有用。點個贊,收個藏唄。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章