nestjs系列一: 前端传输数据的五种形式

487 阅读3分钟

对于前端同学来说,做的最多的就是跟后端联调,联调的过程中涉及到数据的传输,本文总结了前端传输数据的五种方式。分别是:

  • 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>
  `;
  }

那么,浏览器显示的就是一个新的页面。

image.png

当使用POST方法提交表单时,请求体的 content-type 是 application/x-www-form-urlencoded

image.png

form 表单提交数据就不是附加到URL的查询字符串中,而是存放在请求体 body 里。

image.png

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 来取。

image.png

image.png

json

form-urlencoded 需要对内容做 url encode,而 form data 则需要加很长的 boundary,两种方式都有一些缺点。

如果只是传输 json 数据的话,不需要采用这两种方式,采用json格式就行了,这也是前端常用的传输数据的格式,默认的content type 就是application/json, 不需要特别指定。

form urlencoded 和 json 都是从 body 取值,Nest 内部会根据 content type 做区分,使用不同的解析方式。