在前端开发过程中,后端主要提供 http 接口来传输数据,而这种数据传输方式主要有五种:
- url param
- query
- form-urlencoded
- form-data
- json
下面就让我们一起来了解一下在Nest.js中如何使用这五种HTTP数据传输方式:
一,创建项目
使用nest new 创建一个nest的项目
nest new 项目名称
在根目录执行 nest g resource person 快速生成 person 模块的 crud 代码
nest g resource person
nest start --watch 启动 Nest 服务
这样一个有 person 的 crud 接口的服务就跑起来了
二,访问静态资源
api 接口跑通了,再支持下静态资源的访问
main.ts 是负责启动 Nest 的 ioc 容器的,调用下 useStaticAssets 来支持静态资源的请求:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
async function bootstrap() {const app = await NestFactory.create<NestExpressApplication>(AppModule);app.useStaticAssets('public', { prefix: '/static'});await app.listen(3000);
}
bootstrap();
//注意:要给 create 方法传入 NestExpressApplication 的泛型参数才有 useStaticAssets这些方法
我们指定 prefix 为 static,然后在静态文件目录 public 下添加一个 html
api 接口和静态资源的访问都支持了,接下来就分别实现下 5 种前后端 http 数据传输的方式
三,url param
url param 是 url 中的参数,Nest 里通过 :参数名 的方式来声明(比如下面的 :id),然后通过 @Param(参数名) 的装饰器取出来注入到 controller:
@Controller('person') 的路由和 @Get(':id') 的路由会拼到一起,也就是只有 /person/xxx 的 get 请求才会走到这个方法。
接下来我们在前端页面中使用axios请求一下这个接口:
在页面中使用axios发起一个get请求,参数放在url中
<!DOCTYPE html>
<html lang="en"><head><script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
</head><body><script>async function urlParam() {// 使用axios发起请求const res = await axios.get('/person/10086');console.log(res);}urlParam();</script>
</body>
启动服务,在浏览器访问下:
控制台打印了服务端返回的消息,证明服务端拿到了通过 url param 传递的数据。
四,query
query 是 url 中 ? 后的字符串,需要做 url encode。
在 Nest 里,通过 @Query 装饰器来取:
注意:这个 find 的路由要放到 :id 的路由前面,因为 Nest 是从上往下匹配的,如果放在后面,那就匹配到 :id 的路由了。
接下来就在前端页面中去请求这个接口:
<!DOCTYPE html>
<html lang="en"><head><script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
</head><body><script>async function urlParam() {// 使用axios发起请求const res = await axios.get('/person/find',{params:{name:'张三',age:25}});console.log(res);}urlParam();</script>
</body>
参数通过 params 指定,axios 会做 url encode,不需要自己做。
让我们测试一下,服务端成功接受了我们通过 query 传递的数据。
上面两种(url param、query)是通过 url 传递数据的方式,下面 3 种是通过 body 传递数据
五,form urlencoded
form urlencoded 是通过 body 传输数据,其实是把 query 字符串放在了 body 里。
用 Nest 接收的话,使用 @Body 装饰器,Nest 会解析请求体,然后注入到 dto 中。
dto 是 data transfer object,就是用于封装传输的数据的对象:
前端代码使用 post 方式请求,指定 content type 为 application/x-www-form-urlencoded
,用 qs 做下 url encode
<!DOCTYPE html>
<html lang="en"><head><script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script><script src="https://unpkg.com/qs@6.10.2/dist/qs.js"></script>
</head><body><script>async function formUrlEncoded() {const res = await axios.post('/person', Qs.stringify({name: '张三',age: 24}), {headers: { 'content-type': 'application/x-www-form-urlencoded' }});console.log(res);}formUrlEncoded();</script>
</body>
测试一下,服务器成功接收到了数据并返回:
六,json
json 需要指定 content-type 为 application/json
,内容会以 JSON 的方式传输,后端代码同样使用 @Body 来接收,不需要做啥变动。form urlencoded 和 json 都是从 body 取值,Nest 内部会根据 content type 做区分,使用不同的解析方式。
前端代码使用 axios 发送 post 请求,默认传输 json 就会指定 content type 为
application/json
,不需要手动指定
<!DOCTYPE html>
<html lang="en"><head><script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
</head><body><script>async function json() {const res = await axios.post('/person', {name: '张三',age: 24});console.log(res);}json();</script>
</body>
测试下,服务端成功接收到了通过 json 传递的数据
七,form data
json 和 form urlencoded 都不适合传递文件,想传输文件要用 form data
Nest 解析 form data 使用 FilesInterceptor 的拦截器,用 @UseInterceptors 装饰器启用,然后通过 @UploadedFiles 来取。非文件的内容,同样是通过 @Body 来取。
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)}`}
}
这一步需要
npm i -D @types/multer
前端代码使用 axios 发送 post 请求,指定 content type 为 multipart/form-data
:
<!DOCTYPE html>
<html lang="en">
<head><script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
</head>
<body><input id="fileInput" type="file" multiple/><script>const fileInput = document.querySelector('#fileInput');async function formData() {const data = new FormData();data.set('name','张三');data.set('age', 24);data.set('file1', fileInput.files[0]);data.set('file2', fileInput.files[1]);const res = await axios.post('/person/file', data, {headers: { 'content-type': 'multipart/form-data' }});console.log(res); }fileInput.onchange = formData;</script>
</body>
</html>
file input 指定 multiple 可以选择多个文件。
测试一下:
服务端接收到了 name 和 age:
去服务器控制台看下:
可以看到,服务器成功的接收到了我们上传的文件
八,总结
我们用 axios 发送请求,使用 Nest 后端服务,实现了 5 种 http/https 的数据传输方式:
其中前两种是 url 中的:
- url param: url 中的参数,Nest 中使用 @Param 来取
- query:url 中 ? 后的字符串,Nest 中使用 @Query 来取
后三种是 body 中的:
- form urlencoded: 类似 query 字符串,只不过是放在 body 中。Nest 中使用 @Body 来取,axios 中需要指定 content type 为
application/x-www-form-urlencoded
,并且对数据用 qs 或者 query-string 库做 url encode - json: json 格式的数据。Nest 中使用 @Body 来取,axios 中不需要单独指定 content type,axios 内部会处理。
- form data:主要用于传输文件,Nest 中要使用 FilesInterceptor 来处理其中的 binary 字段,用 @UseInterceptors 来启用,其余字段用 @Body 来取。axios 中需要指定 content type 为
multipart/form-data
,并且用 FormData 对象来封装传输的内容。
这 5 种 http 的传输数据的方式覆盖了绝大多数开发场景
下一章我们一起深入学习一下Nest的文件上传,大文件切片上传。