Form 表单数据编码解码--encodeURIComponentURLSearchParamsFormData
Posted 奋飛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Form 表单数据编码解码--encodeURIComponentURLSearchParamsFormData相关的知识,希望对你有一定的参考价值。
本文主要讲解,通过 web api 来处理各种参数问题,防止产生安全问题,以及更便利的操作。
先看一个示例:
const response = await fetch(url, {
method: 'POST',
body: `text=${text}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
const json = await response.json()
上述代码会出现一些“安全问题”,如通过 text=${text}
进行 SQL 或 html 注入。
开始之前,先罗列一下我们日常开发中经常用到的“内容类型 – Content-Type,用于指定资源的MIME类型 media type ,定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件。
Content-Type 常用类型 | 说明 |
---|---|
application/x-www-form-urlencoded | 默认,表单数据 |
multipart/form-data | 表单数据(可包含文件数据) |
application/json | json 数据格式 |
image/png | png 图片格式 |
text/html | HTML格式 |
text/plain | 纯文本格式 |
更多类型,可参考 MIME types 列表
encodeURIComponent
<form>
表单请求默认格式 x-www-form-urlencoded,将表单内的数据转换为键值对,如 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>文章标题:<input type="text" name="title" value="" /></label></p>
<p><label>文章内容:<textarea name="content" rows="5" cols="33"></textarea></label></p>
<p><button type="submit">提交</button></p>
</form>
注意: 由于历史的原因,表单使用的 Url 编码实现并不符合最新的标准,将空格处理成了 + 。
// 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=你好&content=this post about x-www-form-urlencoded')
MIME 类型的数据是 application/x-www-form-urlencoded 时,在 HTML 和 XForms 规范中定义仍然采用早期版本,用“+”代替“%20”替换空格。-- URL encoding the space character: + or %20?
业务中,我们通常不是通过 action 的方式发送,而是通过 ajax/fetch 方式进行封装处理,此时需要对数据进行编码或解码操作。
// title=%E4%BD%A0%E5%A5%BD&content=this%20post%20about%20x-www-form-urlencoded
params = `title=${encodeURIComponent('你好')}&content=${encodeURIComponent('this post about x-www-form-urlencoded')}`
注意: 空格的处理结果 encodeURIComponent(" ") // %20
encodeURI:自身无法产生能适用于HTTP GET 或 POST 请求的URI,例如对于 XMLHTTPRequests,因为 “&”, “+”, 和 “=” 不会被编码,然而在 GET 和 POST 请求中它们是特殊字符
URLSearchParams
通过encodeURIComponent()
和decodeURIComponent()
可以完成相关参数的编码、解码工作,但整体操作和处理都比较复杂,特别是在参数众多,需要获取指定参数的过程中。
function enhanceUrlArgs(query){
var args = {};
query.replace(/([^?&=]+)=([^&]+)/g, function(full, key, value){
args[key] = decodeURIComponent(value);
return "";
});
return args;
}
// {title: "你好", content: "this post about x-www-form-urlencoded"}
enhanceUrlArgs(new URL('https://example.com/?title=你好&content=this post about x-www-form-urlencoded').search)
可以通过 URLSearchParams 处理编码和解码 application/x-www-form-urlencoded 数据,处理方式大大简化。
示例:模拟上述 from 表达提交形式
const searchParams = new URLSearchParams()
searchParams.set('title', '你好')
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())
注意:这个和 form 表单默认处理一致!
构造函数也可以接受“键/值对数组”
new URLSearchParams([
['title', '你好'],
['content', 'this post about x-www-form-urlencoded']
])
再者,也可以是“对象”
new URLSearchParams({
title: '你好',
content: 'this post about x-www-form-urlencoded'
})
还可以是“字符串”
new URLSearchParams('title=你好&content=this post about x-www-form-urlencoded') // location.search
读取方式
和设置方式一一对应
示例:获取上述表单数据
for (const [key, value] of searchParams) {
console.log(key, value)
}
得到“数组”
// [ ['title', '你好'], ['content', 'this post about x-www-form-urlencoded']]
[...searchParams]
得到“对象”
// {title: "你好", content: "this post about x-www-form-urlencoded"}
Object.fromEntries(searchParams)
Object.fromEntries(iterable) 方法把键值对列表转换为一个对象。
需要注意,对象的key是唯一的,可能出现有损转换
const searchParams2 = new URLSearchParams([
['category', 'javascript'],
['category', '前端']
])
// "category=javascript&category=%E5%89%8D%E7%AB%AF"
searchParams2.toString()
// {category: "前端"}
Object.fromEntries(searchParams2)
后者覆盖前者。对于表达 from
提交时,类似 select multiple 是真实存在的,需要格外注意。
避免有损转换:
Object.fromEntries(
[...new Set(searchParams2.keys())].map(key => [key, searchParams2.getAll(key)])
)
获取指定数据
方法 | 说明 |
---|---|
searchParams.entries() | 返回一个iterator 可以遍历所有键/值对的对象。 |
searchParams.get(key) | 获取指定搜索参数的第一个值 |
searchParams.getAll(key) | 获取指定搜索参数的所有值,返回是一个数组 |
searchParams.has(key) | 判断是否存在此搜索参数 |
searchParams.keys() | 返回一个iterator 包含了键/值对的所有键名 |
searchParams.values() | 返回一个iterator 包含了键/值对的所有值 |
示例改写
const response = await fetch(url, {
method: 'POST',
body: new URLSearchParams({ text })
})
const json = await response.json()
使用 URLSearchParams
作为 body,则 Content-Type 标头会自动设置为 application/x-www-form-urlencoded。
FormData
如果表单中包含文件怎么办?application/x-www-form-urlencoded 不支持文件,可以设置为 multipart/form-data 来支持。如果此时需要通过 ajax/fetch 发送请求,可以借助 FormData 进行封装数据。
FormData
接口提供了一种表示表单数据的键值对 key/value
的构造方式,并且可以轻松的将数据通过XMLHttpRequest.send()
方法发送出去,本接口和此方法都相当简单直接。如果送出时的编码类型被设为 "multipart/form-data"
,它会使用和表单一样的格式。
示例:模拟上述 from 表达提交形式
const formData = new FormData()
formData.set('title', '你好')
formData.set('content', 'this post about multipart-form-data')
formData.set('logo', document.forms[1].logo.files[0]) // document.forms[1].logo => fileInputElement
构造函数支持通过 form 表单元素,自动将form中的表单值也包含进去,包括文件内容也会被编码之后包含进去。
new FormData(document.forms[0])
读取方式
示例:获取上述表单数据
for (const [key, value] of formData) {
console.log(key, value)
}
其他方式暂时不支持,获取指定数据方式类似 **URLSearchParams **,且也提供了想对应的方法,可自行查阅。
改写示例
const formData = new FormData();
formData.set('text', text);
const response = await fetch(url, {
method: 'POST',
body: formData
})
const json = await response.json()
使用 FormData
作为 body,则 Content-Type 标头会自动设置为 multipart/form-data。
FormData 转换为 URLSearchParams
form 表单想通过 application/x-www-form-urlencoded 发送。
-
通过上述示例,直接在 form 中增加 action
-
进行转换
const formElement = document.querySelector('form') const formData = new FormData(formElement) const searchParams = new URLSearchParams(formData) fetch(url, { method: 'POST', body: searchParams, })
该方式,文件类型会被丢失。
其他类型
Blobs
fetch(url, {
method: 'POST',
body: blob
})
Content-Type 标头会自动设置为 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' }
})
总结
如果不包含文件,且带有查询参数,可以使用 **URLSearchParams **;如果包含文件,需要使用 FormData。
以上是关于Form 表单数据编码解码--encodeURIComponentURLSearchParamsFormData的主要内容,如果未能解决你的问题,请参考以下文章
jQuery使用serialize()表单序列化时出现中文乱码问题的解决办法