NestJS实战07:集成百度网盘API的全流程指南

作者:热心市民鹿先生2025.11.04 21:02浏览量:1

简介:本文详细解析如何在NestJS中调用百度网盘API,涵盖环境配置、鉴权机制、核心接口实现及错误处理,提供完整代码示例与最佳实践。

NestJS实战07:集成百度网盘API的全流程指南

一、技术背景与需求分析

在构建企业级文件管理系统时,集成第三方云存储服务成为刚需。百度网盘开放平台提供的API接口(如文件上传/下载、目录管理、分享链接生成等)可显著降低开发成本。NestJS作为基于TypeScript的后端框架,其模块化架构和依赖注入特性非常适合封装第三方服务。本方案通过构建独立的服务模块,实现与百度网盘API的无缝对接。

二、开发环境准备

2.1 百度开发者平台配置

  1. 访问百度开发者中心创建应用
  2. 获取API Key和Secret Key(需企业认证)
  3. 启用”网盘存储服务”并配置IP白名单
  4. 记录Access Key和Secret Key(建议使用KMS加密存储)

2.2 NestJS项目初始化

  1. npm i -g @nestjs/cli
  2. nest new baidu-drive-integration
  3. cd baidu-drive-integration
  4. npm install axios @nestjs/config

三、鉴权机制实现

百度网盘API采用OAuth2.0鉴权,需通过以下步骤获取access_token:

3.1 创建AuthService

  1. // src/auth/auth.service.ts
  2. import { Injectable } from '@nestjs/common';
  3. import axios from 'axios';
  4. import { ConfigService } from '@nestjs/config';
  5. @Injectable()
  6. export class AuthService {
  7. constructor(private configService: ConfigService) {}
  8. async getAccessToken(): Promise<string> {
  9. const url = 'https://openapi.baidu.com/oauth/2.0/token';
  10. const params = {
  11. grant_type: 'client_credentials',
  12. client_id: this.configService.get('BAIDU_API_KEY'),
  13. client_secret: this.configService.get('BAIDU_SECRET_KEY'),
  14. };
  15. try {
  16. const response = await axios.get(url, { params });
  17. return response.data.access_token;
  18. } catch (error) {
  19. throw new Error(`Auth failed: ${error.message}`);
  20. }
  21. }
  22. }

3.2 配置环境变量

  1. # .env
  2. BAIDU_API_KEY=your_api_key
  3. BAIDU_SECRET_KEY=your_secret_key

四、核心API封装

4.1 文件上传实现

  1. // src/baidu-drive/baidu-drive.service.ts
  2. import { Injectable } from '@nestjs/common';
  3. import axios from 'axios';
  4. import { AuthService } from '../auth/auth.service';
  5. @Injectable()
  6. export class BaiduDriveService {
  7. constructor(private authService: AuthService) {}
  8. async uploadFile(filePath: string, path: string): Promise<{ file_id: string }> {
  9. const accessToken = await this.authService.getAccessToken();
  10. const url = 'https://pan.baidu.com/rest/2.0/pcs/file';
  11. // 百度网盘API要求使用multipart/form-data
  12. const formData = new FormData();
  13. formData.append('method', 'upload');
  14. formData.append('access_token', accessToken);
  15. formData.append('path', path);
  16. formData.append('file', createReadStream(filePath));
  17. try {
  18. const response = await axios.post(url, formData, {
  19. headers: formData.getHeaders()
  20. });
  21. return response.data;
  22. } catch (error) {
  23. throw new Error(`Upload failed: ${error.response?.data?.error_msg || error.message}`);
  24. }
  25. }
  26. }

4.2 文件列表查询

  1. async listFiles(path: string = '/'): Promise<Array<{ path: string, size: number }>> {
  2. const accessToken = await this.authService.getAccessToken();
  3. const url = 'https://pan.baidu.com/rest/2.0/pcs/file';
  4. const params = {
  5. method: 'list',
  6. access_token: accessToken,
  7. path: encodeURIComponent(path)
  8. };
  9. const response = await axios.get(url, { params });
  10. return response.data.list;
  11. }

五、高级功能实现

5.1 秒传链接生成

  1. async getRapidUploadInfo(fileMd5: string, size: number): Promise<{ rapid_upload: boolean }> {
  2. const accessToken = await this.authService.getAccessToken();
  3. const url = 'https://pan.baidu.com/rest/2.0/pcs/file';
  4. const params = {
  5. method: 'precreate',
  6. access_token: accessToken,
  7. path: `/temp/${Date.now()}`,
  8. size: size,
  9. content-md5: fileMd5,
  10. isdir: 0
  11. };
  12. try {
  13. const response = await axios.post(url, null, { params });
  14. return response.data;
  15. } catch (error) {
  16. if (error.response?.data?.error_code === 31066) {
  17. // 文件已存在,可直接创建秒传链接
  18. return { rapid_upload: true };
  19. }
  20. throw error;
  21. }
  22. }

5.2 批量操作优化

  1. async batchOperations(operations: Array<{ method: string, params: object }>) {
  2. const accessToken = await this.authService.getAccessToken();
  3. const url = 'https://pan.baidu.com/rest/2.0/pcs/batch';
  4. const batchParams = {
  5. access_token: accessToken,
  6. requests: operations.map(op => ({
  7. method: op.method,
  8. ...op.params
  9. }))
  10. };
  11. return axios.post(url, batchParams);
  12. }

六、错误处理与重试机制

6.1 自定义异常过滤器

  1. // src/baidu-drive/exceptions/baidu-drive.exception.ts
  2. export class BaiduDriveException extends HttpException {
  3. constructor(errorCode: number, message: string) {
  4. super({
  5. errorCode,
  6. message,
  7. documentation: 'https://developer.baidu.com/doc/PAN/s/9k3h7x6q2'
  8. }, HttpStatus.BAD_REQUEST);
  9. }
  10. }

6.2 指数退避重试策略

  1. async safeRequest<T>(
  2. requestFn: () => Promise<T>,
  3. maxRetries = 3
  4. ): Promise<T> {
  5. let retryCount = 0;
  6. while (retryCount <= maxRetries) {
  7. try {
  8. return await requestFn();
  9. } catch (error) {
  10. if (retryCount === maxRetries) throw error;
  11. const delay = Math.min(1000 * Math.pow(2, retryCount), 5000);
  12. await new Promise(resolve => setTimeout(resolve, delay));
  13. retryCount++;
  14. }
  15. }
  16. }

七、性能优化建议

  1. Token缓存:使用@nestjs/cache-manager缓存access_token(默认有效期30天)
  2. 并发控制:限制同时上传文件数(建议≤5个)
  3. 断点续传:实现分片上传逻辑(百度API支持slice参数)
  4. 监控告警:集成Prometheus监控API调用成功率

八、完整模块示例

  1. // src/baidu-drive/baidu-drive.module.ts
  2. import { Module } from '@nestjs/common';
  3. import { BaiduDriveService } from './baidu-drive.service';
  4. import { AuthService } from '../auth/auth.service';
  5. import { ConfigModule } from '@nestjs/config';
  6. @Module({
  7. imports: [ConfigModule],
  8. providers: [BaiduDriveService, AuthService],
  9. exports: [BaiduDriveService]
  10. })
  11. export class BaiduDriveModule {}

九、安全注意事项

  1. 永远不要将Secret Key硬编码在代码中
  2. 使用HTTPS协议进行所有API调用
  3. 限制API调用频率(百度网盘API限制6QPS)
  4. 定期轮换API Key和Secret Key

十、测试用例示例

  1. // src/baidu-drive/test/baidu-drive.service.spec.ts
  2. describe('BaiduDriveService', () => {
  3. let service: BaiduDriveService;
  4. const mockAuthService = { getAccessToken: jest.fn() };
  5. beforeEach(async () => {
  6. const module: TestingModule = await Test.createTestingModule({
  7. providers: [
  8. BaiduDriveService,
  9. { provide: AuthService, useValue: mockAuthService }
  10. ],
  11. }).compile();
  12. service = module.get<BaiduDriveService>(BaiduDriveService);
  13. });
  14. it('should upload file successfully', async () => {
  15. mockAuthService.getAccessToken.mockResolvedValue('test_token');
  16. // 模拟axios响应
  17. jest.spyOn(axios, 'post').mockResolvedValue({ data: { file_id: '123' } });
  18. const result = await service.uploadFile('/tmp/test.txt', '/test/');
  19. expect(result).toEqual({ file_id: '123' });
  20. });
  21. });

十一、部署建议

  1. 使用Docker容器化部署
  2. 配置健康检查端点
  3. 设置合理的超时时间(百度API建议30秒)
  4. 启用请求日志记录

通过以上实现,开发者可以在NestJS应用中高效、安全地集成百度网盘API。实际开发中,建议根据业务需求进一步封装业务逻辑,例如实现文件版本控制、自动清理过期文件等高级功能。