前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Form 表单数据编码、解码--encodeURIComponent、URLSearchParams、FormData

Form 表单数据编码、解码--encodeURIComponent、URLSearchParams、FormData

作者头像
奋飛
发布2021-12-30 20:58:09
1.2K0
发布2021-12-30 20:58:09
举报
文章被收录于专栏:Super 前端Super 前端

本文主要讲解,通过 web api 来处理各种参数问题,防止产生安全问题,以及更便利的操作。

先看一个示例:

代码语言:javascript
复制
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

表单请求默认格式 x-www-form-urlencoded,将表单内的数据转换为键值对,如 title=%E4%BD%A0%E5%A5%BD&content=this+post+about+x-www-form-urlencoded

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
<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 方式进行封装处理,此时需要对数据进行编码或解码操作。

代码语言:javascript
复制
// 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() 可以完成相关参数的编码、解码工作,但整体操作和处理都比较复杂,特别是在参数众多,需要获取指定参数的过程中。

代码语言:javascript
复制
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 表达提交形式

代码语言:javascript
复制
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 表单默认处理一致!

构造函数也可以接受“键/值对数组”

代码语言:javascript
复制
new URLSearchParams([
  ['title', '你好'],
  ['content', 'this post about x-www-form-urlencoded']
])

再者,也可以是“对象”

代码语言:javascript
复制
new URLSearchParams({
  title: '你好',
  content: 'this post about x-www-form-urlencoded'
})

还可以是“字符串”

代码语言:javascript
复制
new URLSearchParams('title=你好&content=this post about x-www-form-urlencoded')	// location.search
读取方式

和设置方式一一对应

示例:获取上述表单数据

代码语言:javascript
复制
for (const [key, value] of searchParams) {
  console.log(key, value)
}

得到“数组”

代码语言:javascript
复制
// [ ['title', '你好'], ['content', 'this post about x-www-form-urlencoded']]
[...searchParams] 

得到“对象”

代码语言:javascript
复制
// {title: "你好", content: "this post about x-www-form-urlencoded"}
Object.fromEntries(searchParams) 

Object.fromEntries(iterable) 方法把键值对列表转换为一个对象。

需要注意,对象的key是唯一的,可能出现有损转换

代码语言:javascript
复制
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 是真实存在的,需要格外注意。

避免有损转换:

代码语言:javascript
复制
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包含了键/值对的所有值

示例改写
代码语言:javascript
复制
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 表达提交形式

代码语言:javascript
复制
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中的表单值也包含进去,包括文件内容也会被编码之后包含进去。

代码语言:javascript
复制
new FormData(document.forms[0])
读取方式

示例:获取上述表单数据

代码语言:javascript
复制
for (const [key, value] of formData) {
  console.log(key, value)
}

其他方式暂时不支持,获取指定数据方式类似 **URLSearchParams **,且也提供了想对应的方法,可自行查阅

改写示例
代码语言:javascript
复制
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 发送。

其他类型

Blobs
代码语言:javascript
复制
fetch(url, {
  method: 'POST',
  body: blob
})

Content-Type 标头会自动设置为 Blob.type

Strings
代码语言:javascript
复制
fetch(url, {
  method: 'POST',
  body: JSON.stringify({ hello: 'world' }),
  headers: { 'Content-Type': 'application/json' }
})
Buffers
代码语言:javascript
复制
fetch(url, {
  method: 'POST',
  body: new Uint8Array([]),
  headers: { 'Content-Type': 'image/png' }
})

总结

如果不包含文件,且带有查询参数,可以使用 **URLSearchParams **;如果包含文件,需要使用 FormData

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-08-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • encodeURIComponent
  • URLSearchParams
    • 读取方式
      • 示例改写
      • FormData
        • 读取方式
          • 改写示例
          • FormData 转换为 URLSearchParams
          • 其他类型
            • Blobs
              • Strings
                • Buffers
                • 总结
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档