对于前端同学来说,做的最多的就是跟后端联调,联调的过程中涉及到数据的传输,本文总结了前端传输数据的五种方式。分别是:
- url params
- query
- form-urlencoded
- form-data
- json
下面一一进行介绍。
url params
这种传输方式是把传输的数据放在路径后面,比如:
格式:
http://127.0.0.1/path/:id
示例:
http://127.0.0.1/order/123
这里的 123 就是路径中的参数(url param),服务端框架或者单页应用的路由都支持从 url 中取出参数。
例如,掘金文章请求地址https://juejin.cn/editor/drafts/7386568475488370740
,后面的 7386568475488370740 就是参数。
query
这种方式是把参数添加到 url 的?
后面,并用 & 分隔。比如:
http://127.0.0.1?name=xiaoming&age=20
这里的 name 和 age 就是 query 传递的数据。
如果有非英文的字符和一些特殊字符,则需要要经过编码,可以使用 encodeURIComponent
来编码:
const query = "?name=" + encodeURIComponent('中国') + "&age=5000"
// ?name=%E5%85%89&age=20
或者使用封装了一层的 query-string 库来处理:
const queryString = require('query-string');
queryString.stringify({
name: '中国',
age: 5000
});
// ?name=%E5%85%89&age=20
form-urlencoded
当使用GET
方法提交表单时,表单数据会被附加到URL的查询字符串中,以问号(?
)开始,键值对之间用与号(&
)分隔,每个键值对由等号(=
)连接,也就是 query 的形式。例如:
// 前端代码
<form action="/api/people/urlform" method="get">
<input type="text" name="name" value="pcj" />
<input type="text" name="age" value="123456" />
<button type="submit">Submit</button>
</form>
当点击提交的时候,浏览器的地址会变为http://localhost:3000/api/people/urlform?name=%E6%8D%A7%E5%9C%BA%E5%86%9B&age=123456
。
因为传输参数也是 query 字符串,所以也要用 encodeURIComponent
或者 query-string
库处理下。如果传递大量的数据,比如上传文件的时候就不是很合适了,因为文件 encode 一遍的话太慢了,这时候就可以用 form-data。
这里需要注意的是,是浏览器的地址变为我们请求的地址了,如果我们请求的结果是一个html字符串,那么就会返回一个新页面。
以nestjs
服务端代码为例,/api/people/urlform
返回了一串html字符串。
@Get('urlform')
findAll(@Query('name') name: string, @Query('age') age: number) {
return `
<h1>this is html page</h1>
<h2>name:${name}</h2>
<h2>age:${age}</h2>
`;
}
那么,浏览器显示的就是一个新的页面。
当使用POST
方法提交表单时,请求体的 content-type
是 application/x-www-form-urlencoded
。
form 表单提交数据就不是附加到URL的查询字符串中,而是存放在请求体 body 里。
在nestjs
中,使用@Body
装饰器获取:
@Post('urlform')
create(@Body() createPersonDto: CreatePersonDto) {
return `received: ${JSON.stringify(createPersonDto)}`;
}
form-data
form-data 需要指定 content type
为 multipart/form-data
,同时,数据也不是采用url 的方式了,自然也不用再做 url encode。
很明显,这种方式适合传输文件,而且可以传输多个文件。
前端代码如下:
const data = new FormData();
data.set('name', 'john');
data.set('age', 40);
data.set('file1', fileInput.files[0]);
data.set('file2', fileInput.files[1]);
const res = await axios.post('/api/person/file', data, {
headers: { 'content-type': 'multipart/form-data' },
});
后端nestjs
代码如下:
import { AnyFilesInterceptor } from '@nestjs/platform-express';
import { CreatePersonDto } from './dto/create-person.dto';
@Controller('api/person')
export class PersonController {
@Post('file')
@UseInterceptors(AnyFilesInterceptor({
dest: 'uploads/'
}))
body2(@Body() createPersonDto: CreatePersonDto, @UploadedFiles() files: Array<Express.Multer.File>) {
console.log(files);
return `received: ${JSON.stringify(createPersonDto)}`
}
}
nestjs
中要使用 FilesInterceptor
来处理其中的 binary 字段,用 @UseInterceptors 来启用,其余字段用 @Body 来取。
json
form-urlencoded 需要对内容做 url encode,而 form data 则需要加很长的 boundary,两种方式都有一些缺点。
如果只是传输 json 数据的话,不需要采用这两种方式,采用json格式就行了,这也是前端常用的传输数据的格式,默认的content type
就是application/json
, 不需要特别指定。
form urlencoded 和 json 都是从 body 取值,Nest 内部会根据 content type 做区分,使用不同的解析方式。