This article mainly explains how to deal with various parameter problems through web api to prevent security problems and more convenient operation.
Let's take a look at an example:
const response = await fetch(url, { method: 'POST', body: `text=${text}`, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) const json = await response.json()
The above code will have some "security problems", such as SQL or HTML injection through text=${text}.
Before we start, let's list the "content type - content type" often used in our daily development, which is used to specify the MIME type of resources media type , define the type of network file and the code of web page, and decide what form and code the browser will read the file.
Content type common types | explain |
---|---|
application/x-www-form-urlencoded | By default, form data |
multipart/form-data | Form data (can contain file data) |
application/json | json data format |
image/png | png picture format |
text/html | HTML format |
text/plain | Plain text format |
For more types, please refer to MIME types list
encodeURIComponent
< form > the default format of form request is x-www-form-urlencoded, which converts the data in the form into key value pairs, such as title =% E4% BD% A0% E5% a5% BD & content = this + Post + about + x-www-form-urlencoded
<form action="" method="post" target="" enctype="application/x-www-form-urlencoded"> <p><label>Article title:<input type="text" name="title" value="" /></label></p> <p><label>Article content:<textarea name="content" rows="5" cols="33"></textarea></label></p> <p><button type="submit">Submit</button></p> </form>
Note: due to historical reasons, the Url encoding implementation used by the form does not comply with the latest standards, and the spaces are treated as +.
// href: https://example.com/?title=%E4%BD%A0%E5%A5%BD&content=this%20post%20about%20x-www-form-urlencoded new URL('https://example.com/?title = Hello & content = this post about x-www-form-urlencoded ')
When the data of MIME type is application/x-www-form-urlencoded, the definition in HTML and XForms specifications still adopts the earlier version, Replace spaces with "+" instead of "% 20". -- URL encoding the space character: + or %20?
In business, we usually do not send through action, but encapsulate through ajax/fetch. At this time, we need to encode or decode the data.
// title=%E4%BD%A0%E5%A5%BD&content=this%20post%20about%20x-www-form-urlencoded params = `title=${encodeURIComponent('Hello')}&content=${encodeURIComponent('this post about x-www-form-urlencoded')}`
Note: the processing result of spaces encodeuricomponent ("") / /% 20
encodeURI: it cannot generate a URI suitable for HTTP GET or POST requests by itself. For ex amp le, for XMLHTTPRequests, because "&", "+", and "=" will not be encoded, but they are special characters in GET and POST requests
URLSearchParams
Encoding and decoding of relevant parameters can be completed through encodeURIComponent() and decodeURIComponent(), but the overall operation and processing are complex, especially in the process of obtaining specified parameters due to many parameters.
function enhanceUrlArgs(query){ var args = {}; query.replace(/([^?&=]+)=([^&]+)/g, function(full, key, value){ args[key] = decodeURIComponent(value); return ""; }); return args; } // {title: "hello", content: "this post about x-www-form-urlencoded"} enhanceUrlArgs(new URL('https://example.com/?title = Hello & content = this post about x-www-form-urlencoded ') search)
application/x-www-form-urlencoded data can be encoded and decoded through URLSearchParams, and the processing method is greatly simplified.
Example: simulate the above from expression submission form
const searchParams = new URLSearchParams() searchParams.set('title', 'Hello') searchParams.set('content', 'this post about x-www-form-urlencoded') // title=%E4%BD%A0%E5%A5%BD&content=this+post+about+x-www-form-urlencoded console.log(searchParams.toString())
Note: This is consistent with the default processing of the form!
Constructors can also accept an array of key / value pairs
new URLSearchParams([ ['title', 'Hello'], ['content', 'this post about x-www-form-urlencoded'] ])
Furthermore, it can also be "object"
new URLSearchParams({ title: 'Hello', content: 'this post about x-www-form-urlencoded' })
It can also be a "string"
new URLSearchParams('title=Hello&content=this post about x-www-form-urlencoded') // location.search
Read mode
It corresponds to the setting method one by one
Example: get the above form data
for (const [key, value] of searchParams) { console.log(key, value) }
Get "array"
// [['title ',' hello '], ['content', 'this post about x-www-form-urlencoded']] [...searchParams]
Get "object"
// {title: "hello", content: "this post about x-www-form-urlencoded"} Object.fromEntries(searchParams)
Object. The fromentries (Iterable) method converts the list of key value pairs into an object.
It should be noted that the key of the object is unique, and lossy conversion may occur
const searchParams2 = new URLSearchParams([ ['category', 'javascript'], ['category', 'front end'] ]) // "category=javascript&category=%E5%89%8D%E7%AB%AF" searchParams2.toString() // {category: "front end"} Object.fromEntries(searchParams2)
The latter covers the former. When expressing from submission, select multiple is real and needs special attention.
Avoid lossy conversions:
Object.fromEntries( [...new Set(searchParams2.keys())].map(key => [key, searchParams2.getAll(key)]) )
Get specified data
method | explain |
---|---|
searchParams.entries() | Return a iterator Objects that can traverse all key / value pairs. |
searchParams.get(key) | Gets the first value of the specified search parameter |
searchParams.getAll(key) | Gets all the values of the specified search parameters and returns an array |
searchParams.has(key) | Determine whether this search parameter exists |
searchParams.keys() | Returns an iterator containing all key names of key / value pairs |
searchParams.values() | Returns an iterator that contains all the values of a key / value pair |
Sample rewrite
const response = await fetch(url, { method: 'POST', body: new URLSearchParams({ text }) }) const json = await response.json()
If URLSearchParams is used as the body, the content type header will be automatically set to application/x-www-form-urlencoded.
FormData
What if the form contains files? application/x-www-form-urlencoded does not support files. It can be set to multipart / form data. If you need to send a request through ajax/fetch at this time, you can encapsulate the data with FormData.
The FormData interface provides a way to construct key/value pairs that represent form data, and can easily pass data through XMLHttpRequest.send() Method. Both this interface and this method are quite simple and direct. If the encoding type when sending is set to "multipart / form data", it will use the same format as the form.
Example: simulate the above from expression submission form
const formData = new FormData() formData.set('title', 'Hello') formData.set('content', 'this post about multipart-form-data') formData.set('logo', document.forms[1].logo.files[0]) // document.forms[1].logo => fileInputElement
The constructor supports automatically including the form value in the form through the form element, including the file content, which will also be included after encoding.
new FormData(document.forms[0])
Read mode
Example: get the above form data
for (const [key, value] of formData) { console.log(key, value) }
Other methods are not supported temporarily. The method of obtaining the specified data is similar to * * URLSearchParams * *, and the corresponding method is also provided. You can Self access.
Rewrite example
const formData = new FormData(); formData.set('text', text); const response = await fetch(url, { method: 'POST', body: formData }) const json = await response.json()
If FormData is used as the body, the content type header will be automatically set to multipart / form data.
Convert FormData to URLSearchParams
The form wants to be sent through application/x-www-form-urlencoded.
-
Through the above example, add action directly to the form
-
Convert
const formElement = document.querySelector('form') const formData = new FormData(formElement) const searchParams = new URLSearchParams(formData) fetch(url, { method: 'POST', body: searchParams, })
In this way, the file type will be lost.
Other types
Blobs
fetch(url, { method: 'POST', body: blob })
The content type header is automatically set to Blob.type
Strings
fetch(url, { method: 'POST', body: JSON.stringify({ hello: 'world' }), headers: { 'Content-Type': 'application/json' } })
Buffers
fetch(url, { method: 'POST', body: new Uint8Array([]), headers: { 'Content-Type': 'image/png' } })
summary
If there are no files and query parameters, you can use * * URLSearchParams * *; If you include files, you need to use FormData.