进阶全栈的第一步:能实现这五种接口

开发
如果你想成为一名全栈工程师,那么不能满足于会写这几种方式的前端代码,后端代码也得会写。所以,这篇文章我们来实现下前后端代码,把整个链路打通,真正掌握它们。

上一篇文章我们总结了网页开发的 5 种 http/https 传输数据的方式:

  • url param
  • query
  • form urlencoded
  • form data
  • json

这 5 种方式覆盖了开发中绝大多数场景,掌握好这些就能轻松应对各种 http/https 数据通信的需求。

如果你想成为一名全栈工程师,那么不能满足于会写这几种方式的前端代码,后端代码也得会写。

所以,这篇文章我们来实现下前后端代码,把整个链路打通,真正掌握它们。

前端使用 axios 发送请求,后端使用 Nest.js 作为服务端框架。

准备工作

首先我们要把 Nest.js 服务端跑起来,并且支持 api 接口、静态页面。

Nest.js 创建一个 crud 服务是非常快的,只需要这么几步:

  • 安装 @nest/cli,使用 nest new xxx 创建一个 Nest.js 的项目,
  • 在根目录执行 nest g resource person 快速生成 person 模块的 crud 代码
  • npm run start 启动 Nest.js 服务

这样一个有 person 的 crud 接口的服务就跑起来了,是不是非常快。

服务跑起来以后是这样的

打印出了有哪些接口可以用,可以在 postman 或者浏览器来测试下:

api 接口跑通了,再支持下静态资源的访问:

main.ts 是负责启动 Nest.js 的 ioc 容器的,在脚手架生成的代码的基础上,调用下 useStaticAssets 就可以支持静态资源的请求。

  1. async function bootstrap() { 
  2.   const app = await NestFactory.create<NestExpressApplication>(AppModule); 
  3.   app.useStaticAssets(join(__dirname, '..''public'), { prefix: '/static'}); 
  4.   await app.listen(3000); 
  5. bootstrap(); 

我们指定 prefix 为 static,然后再静态文件目录 public 下添加一个 html:

  1. <html> 
  2. <body>hello</body> 
  3. </html> 

重启服务,然后浏览器访问下试试:

api 接口和静态资源的访问都支持了,接下来就分别实现下 5 种前后端 http 数据传输的方式吧。

url param

url param 是 url 中的参数,Nest.js 里通过 :参数名 的方式来声明,然后通过 @Param(参数名) 的装饰器取出来注入到 controller:

  1. @Controller('api/person'
  2. export class PersonController { 
  3.   @Get(':id'
  4.   urlParm(@Param('id') id: string) { 
  5.     return `received: id=${id}`; 
  6.   } 

前端代码就是一个 get 方法,参数放在 url 里:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script> 
  5. </head> 
  6. <body> 
  7.     <script> 
  8.         async function urlParam() { 
  9.             const res = await axios.get('/api/person/1'); 
  10.             console.log(res);             
  11.         } 
  12.         urlParam(); 
  13.    </script> 
  14. </body> 

启动服务,在浏览器访问下:

控制台打印了服务端返回的消息,证明服务端拿到了通过 url param 传递的数据。

通过 url 传递数据的方式除了 url param 还有 query:

query

query 是 url 中 ? 后的字符串,需要做 url encode。

在 Nest.js 里,通过 @Query 装饰器来取:

  1. @Controller('api/person'
  2. export class PersonController { 
  3.   @Get('find'
  4.   query(@Query('name'name: string, @Query('age') age: number) { 
  5.     return `received: name=${name},age=${age}`; 
  6.   } 

前端代码同样是通过 axios 发送一个 get 请求:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script> 
  5. </head> 
  6. <body> 
  7.     <script> 
  8.         async function query() { 
  9.             const res = await axios.get('/api/person/find', { 
  10.                 params: { 
  11.                     name'光'
  12.                     age: 20 
  13.                 } 
  14.             }); 
  15.             console.log(res);             
  16.         } 
  17.         query(); 
  18.    </script> 
  19. </body> 
  20. </html> 

参数通过 params 指定,axios 会做 url encode,不需要自己做。

然后测试下:

服务端成功接受了我们通过 query 传递的数据。

上面两种(url param、query)是通过 url 传递数据的方式,下面 3 种是通过 body 传递数据。

html urlencoded

html urlencoded 是通过 body 传输数据,其实是把 query 字符串放在了 body 里,所以需要做 url encode:

用 Nest.js 接收的话,使用 @Body 装饰器,Nest.js 会解析请求体,然后注入到 dto 中。

dto 是 data transfer object,就是用于封装传输的数据的对象:

  1. export class CreatePersonDto { 
  2.     name: string; 
  3.     age: number; 
  1. import { CreatePersonDto } from './dto/create-person.dto'
  2.  
  3. @Controller('api/person'
  4. export class PersonController { 
  5.   @Post() 
  6.   body(@Body() createPersonDto: CreatePersonDto) { 
  7.     return `received: ${JSON.stringify(createPersonDto)}` 
  8.   } 

前端代码使用 post 方式请求,指定 content type 为 application/x-www-form-urlencoded,用 qs 做下 url encode:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script> 
  5.     <script src="https://unpkg.com/qs@6.10.2/dist/qs.js"></script> 
  6. </head> 
  7. <body> 
  8.     <script> 
  9.         async function formUrlEncoded() { 
  10.             const res = await axios.post('/api/person', Qs.stringify({ 
  11.                 name'光'
  12.                 age: 20 
  13.             }), { 
  14.                 headers: { 'content-type''application/x-www-form-urlencoded' } 
  15.             }); 
  16.             console.log(res);   
  17.         } 
  18.  
  19.         formUrlEncoded(); 
  20.     </script> 
  21. </body> 
  22. </html> 

测试下:

服务端成功的接收到了数据。

其实比起 form urlencoded,使用 json 来传输更常用一些:

json

json 需要指定 content-type 为 application/json,内容会以 JSON 的方式传输:

后端代码同样使用 @Body 来接收,不需要做啥变动。form urlencoded 和 json 都是从 body 取值,Nest.js 内部会根据 content type 做区分,使用不同的解析方式。

  1. @Controller('api/person'
  2. export class PersonController { 
  3.   @Post() 
  4.   body(@Body() createPersonDto: CreatePersonDto) { 
  5.     return `received: ${JSON.stringify(createPersonDto)}` 
  6.   } 

前端代码使用 axios 发送 post 请求,默认传输 json 就会指定 content type 为 application/json,不需要手动指定:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script> 
  5. </head> 
  6. <body> 
  7.     <script> 
  8.         async function json() { 
  9.             const res = await axios.post('/api/person', { 
  10.                 name'光'
  11.                 age: 20 
  12.             }); 
  13.             console.log(res);      
  14.         } 
  15.         json(); 
  16.     </script> 
  17. </body> 
  18. </html> 

测试下:

服务端成功接收到了通过 json 传递的数据。

json 和 form urlencoded 都不适合传递文件,想传输文件要用 form data:

form data

form data 是用 -------- 作为 boundary 分隔传输的内容的:

Nest.js 解析 form data 使用 FilesInterceptor 的拦截器,用 @UseInterceptors 装饰器启用,然后通过 @UploadedFiles 来取。非文件的内容,同样是通过 @Body 来取。

  1. import { AnyFilesInterceptor } from '@nestjs/platform-express'
  2. import { CreatePersonDto } from './dto/create-person.dto'
  3.  
  4. @Controller('api/person'
  5. export class PersonController { 
  6.   @Post('file'
  7.   @UseInterceptors(AnyFilesInterceptor()) 
  8.   body2(@Body() createPersonDto: CreatePersonDto, @UploadedFiles() files: Array<Express.Multer.File>) { 
  9.     console.log(files); 
  10.     return `received: ${JSON.stringify(createPersonDto)}` 
  11.   } 

前端代码使用 axios 发送 post 请求,指定 content type 为 multipart/form-data:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script> 
  5. </head> 
  6. <body> 
  7.     <input id="fileInput" type="file" multiple/> 
  8.     <script> 
  9.         const fileInput = document.querySelector('#fileInput'); 
  10.  
  11.         async function formData() { 
  12.             const data = new FormData(); 
  13.             data.set('name','光'); 
  14.             data.set('age', 20); 
  15.             data.set('file1', fileInput.files[0]); 
  16.             data.set('file2', fileInput.files[1]); 
  17.  
  18.             const res = await axios.post('/api/person/file', data, { 
  19.                 headers: { 'content-type''multipart/form-data' } 
  20.             }); 
  21.             console.log(res);      
  22.         } 
  23.  
  24.          
  25.         fileInput.onchange = formData; 
  26.     </script> 
  27. </body> 
  28. </html> 

file input 指定 multiple 可以选择多个文件。

测试下:

服务端接收到了 name 和 age:

去服务器控制台看下:

可以看到,服务器成功的接收到了我们上传的文件。

全部代码上传到了 github:https://github.com/QuarkGluonPlasma/nestjs-exercize

总结

我们用 axios 发送请求,使用 Nest.js 起后端服务,实现了 5 种 http/https 的数据传输方式:

其中前两种是 url 中的:

url param:url 中的参数,Nest.js 中使用 @Param 来取

query:url 中 ? 后的字符串,Nest.js 中使用 @Query 来取

后三种是 body 中的:

form urlencoded:类似 query 字符串,只不过是放在 body 中。Nest.js 中使用 @Body 来取,axios 中需要指定 content type 为 application/x-www-form-urlencoded,并且对数据用 qs 做 url encode

json:json 格式的数据。Nest.js 中使用 @Body 来取,axios 中不需要单独指定 content type,axios 内部会处理。

form data:通过 ----- 作为 boundary 分隔的数据。主要用于传输文件,Nest.js 中要使用 FilesInterceptor 来处理,用 @UseInterceptors 来启用。其余部分用 @Body 来取。axios 中需要指定 content type 为 multipart/form-data,并且用 FormData 对象来封装传输的内容。

这 5 种 http/https 的传输数据的方式覆盖了绝大多数开发场景,如果你想进阶全栈,能够提供这 5 种接口是首先要做到的。

 

责任编辑:武晓燕 来源: 神光的编程秘籍
相关推荐

2021-01-15 18:17:06

网络协议分层

2011-07-25 14:17:46

BSMIT运维北塔

2015-06-02 11:42:00

Cloud FoundAzure

2009-01-18 08:49:04

Java入门JDK

2019-11-20 10:54:46

无密码身份验证网络安全

2013-01-15 09:17:11

2012-07-11 16:43:14

飞视美

2010-07-01 13:44:12

2020-07-22 22:10:34

互联网物联网IOT

2012-08-30 11:14:11

云计算虚拟化

2018-02-10 11:24:39

Python数据程序

2021-08-24 05:07:25

React

2020-11-17 14:55:36

亚马逊云科技迁移

2017-09-19 09:36:55

思科服务

2010-11-05 10:32:50

云应用程序规划

2020-11-11 07:09:05

隔离直播系统

2013-04-03 09:22:14

虚拟化网络虚拟化

2024-02-26 10:08:01

2010-01-21 10:29:54

java认证

2023-06-13 13:51:00

云迁移云平台业务
点赞
收藏

51CTO技术栈公众号