Nestjs用装饰器从0到1实现HTTP Get请求

前言

本文是基于小满zs的nest教学视频的个人学习笔记,大家感兴趣可以去看看原文
xiaoman.blog.csdn.net/article/det…

我们通过axios库发送http请求,首先安装axios

1
sh复制代码npm i axios -S

然后定义一个控制器 Controller

1
2
3
4
5
6
7
8
ts复制代码class Controller {
constructor(){

}
getList(){

}
}

现在我希望Controller的getList()方法可以获取后端API返回的list,同时通过装饰器@GET去发送http请求,getList()方法中不包含任何与网络请求有关的代码。

那么我们要做的第一步,将后端API的URL作为参数传入装饰器函数中,再由装饰器函数发起axios请求,按照正常人想法,既然装饰器本质是一个函数,那我能不能直接将URL作为参数,传入装饰器函数中呢?

1
2
3
4
5
6
7
8
9
10
11
12
ts复制代码const GET:MethodDecorator = (target, key, scriptor, URL:string)=>{
cosnole.log(URL)
}

class Controller{
constructor(){}

@GET("https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10")
getList() {

}
}

image.png
可以发现代码报错,MethodDecorator函数类型的参数是固定的,不能随便添加。
因为TS严格约束数据类型,因此通过|来添加参数的方法并不可取,至少这种投机取巧的方式用的多了,项目便很难维护。所以现在,是高阶函数出场的时候了。

既然我们要将URL作为参数传入装饰器函数,但是装饰器函数不能接收新的参数。我们不妨在外面再套一层函数,最外面的一层函数接收URL,然后返回装饰器函数。由于装饰器函数引用了外层函数的URL,形成了一个闭包!我们的问题完美解决了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ts复制代码const GET = (URL: string):MethodDecorator=>{
return (target, key, scriptor)=>{
console.log(URL)
}
}

class Controller{
constructor(){}

@GET("https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10")
getList() {

}
}

image.png

这种高阶函数就叫做装饰器工厂,装饰器的本质就是一个高阶函数。

接下来我们就可以继续编写装饰器函数中的逻辑:发送HTTP Get请求,然后将结果返回给装饰的getList()函数

这里我们复习一下方法装饰器函数的三个默认参数

  • 原型对象
  • 方法名称
  • 属性描述符
    • 可写:writable
    • 可枚举:enumerable
    • 可配置:configurable
    • ?value:对应的函数

所以我们可以通过descriptor属性描述符的value属性,获取到装饰的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ts复制代码import axios from "axios";

const GET = (url: string): MethodDecorator => {
return (target, key, descriptor) => {
//获取到装饰的函数
const fn = descriptor.value as Function;
//自定义参数status,用来传递状态码
let status = 0
//发送get请求
axios.get(url).then(res => {
//如果get请求发送成功,将返回的结果和其他自定义参数传递给getList函数
status = 200
fn(res, status)
}).catch(err => {
status = 500
fn(err, status)
})
}
}

然后我们使用@Get装饰getList方法,然后再getList函数里接收返回的参数。这句话是什么意思呢?我来解释给你听:
我们再axios发起Get请求后,调用了fn()函数,并往里面传递了一系列参数

1
2
3
4
5
6
7
8
ts复制代码        axios.get(url).then(res => {
//如果get请求发送成功,将返回的结果和其他自定义参数传递给getList函数
status = 200
fn(res, status)
}).catch(err => {
status = 500
fn(err, status)
})

而fn()函数是我们从方法装饰器的属性描述符中获取的

1
2
ts复制代码        //获取到装饰的函数
const fn = descriptor.value as Function;

结合起来就是,fn()函数接收到的参数,会传递给原方法,即被getList()函数接收

1
2
3
4
5
6
7
8
9
10
ts复制代码class Controller {
constructor() { }

@GET("https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10")
//注意这里,我定义了两个参数,这两个参数就是从@GET装饰器传来的
getList(res: any, status: number) {
console.log(res.data)
console.log(status)
}
}

这样通过装饰器实现了,将发送HTTP Get请求的逻辑全部集中到@GET返回的装饰器函数,将Get请求返回的结果处理逻辑,全部集中到了getlist()方法中。

总结

我们通过定义装饰器工厂函数(高阶函数),解决了向装饰器传递自定义参数的问题
通过装饰器,成功将发送Get请求逻辑和处理Get请求逻辑分开

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%