17

Preface

This article aims to record the process of solving puzzles, such as

  1. In the chrome debugging tool, what is the difference between Form Data and Request Payload
  2. What is the difference between application/x-www-form-urlencoded and application/json How should we choose during development?
  3. Why does the backend sometimes fail to parse the data sent by itself?
  4. In the cross-domain request of POST OPTIONS pre-check request?

Not much to say, go directly to the topic.

Found the problem, start with two screenshots

微信请求

掘金请求

These two screenshots are the original intention of writing this article. When the WeChat article is opened, Form Data is displayed. The second picture is a request initiated by the Nuggets when opening the article. At the time, it was very strange to see them, Form Data and Request Payload What's the difference? Why are POST requests, but there are two ways to send data?

I belong to the person who encounters this kind of strange problem and can't sleep without getting him clear. Let's reproduce it directly in the local scene and take a good look at these two goods.

If you don’t want to see the analysis process in the middle, you can directly click summary to see Jay.

Scene reproduction

We started two services locally, front-end and back-end, by creating XMLHttpRequest objects for data transmission, and using setRequestHeader() to change Content-Type , and finally we reproduced the two modes perfectly in the debugging tool.

The sample code in the article can be found in this warehouse. who hope to try it themselves can click to view the details 160a1d538489e2 sample address .

git clone -b demo/study-post-request https://github.com/jsjzh/tiny-codes.git

Request Payload

If you want to see Request Payload , you need to set the request header Content-Type: application/json , and then send the data after serialization of JSON.stringify

chrome application/json

You can see my Origin: http://localhost.charlesproxy.com:3000 here. This is because Charles needs to be used to capture local packets, and this is used as a proxy

Directly upload the screenshot of the package

application/json 抓包

The upper part is a complete http request. Above the blank line is the request header, and below the blank line is the request body. You can see that our request body is a json serialized string.

In the lower part, pay attention to the two tabs JSON and JSON Text Content-Type: application/json , Charles will automatically bring them.

After the backend receives the http request, it is the parsing of the request body after intercepting the blank line. Because we passed Content-Type: application/json , the backend knows that the request body is a json string, so it can be parsed JSON.parse

The data sent is

{
  "name": "king",
  "age": 18,
  "isAdmain": true,
  "groups": [1, 2, 3],
  "address": "",
  "foo": null,
  "bar": undefined,
  "extra": { "wechat": "kimimi_king", "qq": 454075623 }
}

The parsed data is

{
  "name": "king",
  "age": 18,
  "isAdmain": true,
  "groups": [1, 2, 3],
  "address": "",
  "foo": null,
  "extra": { "wechat": "kimimi_king", "qq": 454075623 }
}

It can be seen that in addition to bar: undefined , number , boolean and null , the data types are all correctly transmitted.

Form Data

Let's talk about Form Data , we need to set Content-Type: application/x-www-form-urlencoded , and then qs.stringify before sending.

qs is qs npm source , which is a library for querystring data

It can be simply understood that he can convert an object into a similar get request? The following query field key=data&key2=data2

If you send directly without qs processing, the method will use toString() to convert the data to a string. If you are transmitting an object, you will get [object Object]

chrome application/x-www-form-urlencoded

The screenshot of the packet capture is also posted directly here

application/x-www-form-urlencoded 抓包

The upper part is the http request. You can see that when we set Content-Type: application/x-www-form-urlencoded request body is also placed after the blank line.

In the lower part, compare the application/json just now to find the difference. JSON and JSON Text are gone, replaced by Form tabs.

After the backend receives the http request, it also intercepts the request body after the blank line, and uses qs.parse for parsing.

The data sent is

{
  "name": "king",
  "age": 18,
  "isAdmain": true,
  "groups": [1, 2, 3],
  "address": "",
  "foo": null,
  "bar": undefined,
  "extra": { "wechat": "kimimi_king", "qq": 454075623 }
}

The parsed data is

{
  "name": "king",
  "age": "18",
  "isAdmain": "true",
  "groups": ["1", "2", "3"],
  "address": "",
  "foo": "",
  "extra": { "wechat": "kimimi_king", "qq": "454075623" }
}

After Content-Type: application/json , we can see that not only the data types of number and boolean foo: null also been converted to foo: "" .

Exchange serialization method

Just now we tried the correct Content-Type corresponding to the correct serialization method

application/json + JSON.stringify

application/x-www-form-urlencoded + qs.stringify

But in fact, we observed the actual http request, these two Content-Type are transmitted after the data is placed in a blank line, so of course we can also exchange their serialization methods.

application/json + qs.stringify

image.png

image.png

Here is the conclusion directly, we set application/json , but use qs.stringify serialization, the result is

  1. Request Payload chrome debugging tool cannot be parsed, so the data cannot be formatted
  2. JSON and JSON Text charles tool cannot be parsed
  3. Most importantly, if the backend reads Content-Type as application/json , it will use JSON.parse to parse the data
Of course we can manually use qs.parse for analysis in the backend, but why should we bury ourselves?

application/x-www-form-urlencoded + JSON.stringify

image.png

image.png

In the same way, using Content-Type and incorrect serialization methods, not only chrome and charles cannot be parsed, but also the backend will have doubts, and more importantly, it will bury itself.

to sum up

image.png

Oh, yes, I just want to skin it

So much has been said before, now let’s summarize

  1. Form Data and Request Payload are because the requested Content-Type different, and different presentation methods after parsing the request body
  2. Content-Type set to application/json or application/x-www-urlencoded In the http request, Header , the request body is placed after the blank line

Then how should we choose Content-Type in development? application/json if it is not a special requirement of the project. The reasons are as follows

  1. JSON.stringify native 060a1d53848f3f and JSON.parse not fragrant? There are many implementations of qs in the front end, such as qs and query-string , and node's own querystring
  2. x-www-form-urlencoded needs to use the supporting qs.stringify , backend parsing data will lose the data type , such as number , boolean , null
  3. Different frameworks have qs.parse . There may be front-end and back-end alignment operations when the project is first docked.
  4. The front-end qs warehouse can only handle 5 layers of objects by default, and can only parse 1000 parameters by default (of course, both configurations can be modified), for example
{
  "a": {
    "b": {
      "c": {
        "d": {
          "e": {
            "f": {
              "g": { "name": "king" }
            }
          }
        }
      }
    }
  }
}

Because the number of nested objects is too deep, it becomes as follows after parsing

{
  "a": {
    "b": {
      "c": {
        "d": {
          "e": {
            "[f][g][name]": "king"
          }
        }
      }
    }
  }
}

Of course, application/json , it will be a little different

  1. After configuring the header Content-Type: application/json , it is not a simple request. A Options pre-check request will be initiated.
  2. The back end needs to be configured with Access-Control-Request-Headers: Content-Type synchronously, and the front end is allowed to configure the Content-Type head

Of course, CORS 's talk about the knowledge points of 060a1d53849081. There are also many contents in this area that can be broken down and detailed. I am also sorting out the contents in this area, so I can look forward to it.

Afterword

I don’t know if this article has brought you some help. If so, it’s my honor. When you encounter problems, you can dig deeper, like this time Form Data and Request Payload . When we dig into At the http request level, we can find that there is no difference between the two. It is a kind of encapsulation of the http protocol by the browser, and the correct use of Content-Type is an agreement between us and the back-end joint debugging, and it is also a specification.

Of course, we can set Content-Type , but this requires unnecessary joint debugging with the backend, and it is not convenient for subsequent understanding and maintenance, so we can keep it simple, some frameworks will automatically parse the request body and hair Content-Type Since there are so few, we should not forcefully increase the difficulty of the game.

Footer

Code is life, and I am happy with it.

Technology is constantly changing
Mind is always online
The front end is long
See you next time

by --- Crotch Trio

I am here gayhub@jsjzh welcome everyone to come and play with me.

Welcome friends to add me directly, pull you into the group and do things together, remember to note where you saw the article.

ps: If the picture is invalid, you can add me wechat: kimimi_king

裤裆三重奏
788 声望936 粉丝

认真的灵魂会发光