江夏
主 题
今天,把博客后端从nest8
升级nest9
之后,项目中直接使用axios
请求第三方接口时,发现运行报错axios.get//undefind
。
nest9中http请求需要用到HttpService
来操作。HttpService
是axios
和rxjs
组成的模块。rxjs
结合http
请求不熟悉,遇到了许多坑记录一下。
基本使用
language
import { HttpService } from '@nestjs/axios';
import { catchError, map } from 'rxjs/operators';
export class ResourcesService {
constructor(
@InjectRepository(File) private readonly fileRepository: Repository<File>,
private readonly httpService: HttpService,
) {}
getImg(n = '1') {
const res: any = this.httpService
.get('http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=' + n)
.pipe(map((res) => res.data));
// console.log(res); // 这里直接打印不出来数据格式的,都是映射函数,需要用subscribe观察
// res.subscribe((val) => console.log(val));// 订阅观察了,就可以打印出来
return res;
}
}
多个嵌套请求
复杂的嵌套请求的话,可以把每个请求都封装成promise
来结合async/awai
t使用(这里是封装成单个promise
)。简单嵌套请求的话,可以使用rxjs的pipe和mergeMap配合使用。
1.封装成单个promise
language
import { HttpException, Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Repository } from 'typeorm';
import { File } from './resources.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { catchError, map } from 'rxjs/operators';
@Injectable()
export class ResourcesService {
constructor(
@InjectRepository(File) private readonly fileRepository: Repository<File>,
private readonly httpService: HttpService,
) {}
refresh_token = '';
access_token = '';
async baiDuTongJi(query) {
// 请求数据
let data: any = await this.getDaiDuTongJiData(query);
// console.log('data1', data);
// token 过期 刷新token
if (data.error_code === 110 || data.error_code === 111) {
await this.refreshAccessToken();
// 重新请求数据
data = await this.getDaiDuTongJiData(query);
// console.log('data2', data);
}
return data;
}
// 刷新 统计 access_token
refreshAccessToken() {
return new Promise((resolve) => {
this.httpService
.get(`http://openapi.baidu.com/oauth/2.0/token`, {
params: {
grant_type: 'refresh_token',
refresh_token: this.refresh_token,
client_id: '', // apikey
client_secret: '', // SecretKey
},
})
.pipe(
map((res) => res.data),
catchError((e) => {
throw new HttpException(`刷新access_token错误`, 400);
}),
)
.subscribe((data) => {
this.access_token = data.access_token;
this.refresh_token = data.refresh_token;
resolve(data);
});
});
}
// 获取统计数据
getDaiDuTongJiData(query) {
return new Promise((resolve) => {
const { url, ...otherParams /* 除了url其他组合成一个对象 */ } = query;
this.httpService
.get(`https://openapi.baidu.com${url}`, {
params: {
...otherParams,
access_token: this.access_token,
},
})
.pipe(map((res) => res.data))
.subscribe((data) => resolve(data));
});
}
}
2.使用rxjs
内置的mergeMap
mergeMap 操作符用于从内部的 Observable 对象中获取值,然后返回给父级流对象。
language
import { of } from "rxjs";
import { mergeMap } from "rxjs/operators";
const source$ = of("Hello");
const example$ = source$.pipe(mergeMap(val => of(`${val} World!`)));
const subscribe = example$.subscribe(val => console.log(val));
3.rxjs
的正确用法应该不是封装成promise的,这里是取巧实现了嵌套(修改参数之后)请求
全部评论(0)