使用GraphQL+Nest实现阿里云OSS上传

概述

服务端签名后直传的方式:

服务端签名后直传(Server Signature Direct Upload)是一种安全的文件上传方式,其中文件上传的签名是在服务端生成的,而不是在客户端生成。这样可以防止客户端直接上传文件而绕过服务器的权限控制。

这种方式的优点是可以在服务端进行更细粒度的控制,例如限制上传文件的大小、类型,以及存储路径等。客户端只需要负责文件上传,而上传权限和规则都由服务端掌控。这样可以提高文件上传的安全性和可控性。

安装aliyun的包 ali-oss

json 复制代码
"ali-oss": "^6.17.1",
"dayjs": "^1.11.7",
"buffer": "^6.0.3",

ali-oss (^6.17.1):

ali-oss 是阿里云 OSS(Object Storage Service)的官方 Node.js SDK。

用于在 Node.js 环境中与阿里云 OSS 进行交互,包括上传、下载、删除文件等操作。

允许在应用中直接使用 Node.js 代码访问和管理阿里云 OSS 中的对象。

dayjs (^1.11.7):

dayjs 是一个轻量级的 JavaScript 日期库,用于解析、操作和格式化日期。

与 Moment.js 相比,dayjs 更小巧,性能更好,同时提供了类似的功能,使日期处理更加方便。

buffer (^6.0.3):

buffer 是 Node.js 内置模块,用于处理二进制数据。

提供了对二进制数据的处理和转换功能,包括创建 Buffer 对象、拼接、切片等。

在文件处理、网络通信等场景中常用于处理二进制数据。

这些包在项目中的使用场景可能如下:

  • ali-oss:用于将文件上传到阿里云 OSS 或从 OSS 中下载文件。
  • dayjs:用于处理和格式化日期,提供更轻量级的替代方案。
  • buffer:在处理二进制数据时可能会使用,例如文件上传、数据流处理等。

对于server端,在modules中创建oss文件夹(oss对应的module),

创建oss.module.ts

此处展示完整代码,实际需要先创建oss.service,以及oss.resolver,再进行引入

python 复制代码
import { Module } from '@nestjs/common';
import { OSSService } from './oss.service';
import { OSSResolver } from './oss.resolver';

@Module({
  imports: [],
  providers: [OSSResolver, OSSService],
  exports: [],
})
export class OSSModule {}

providers: [OSSResolver, OSSService]: providers 数组包含了该模块提供的服务提供者。在这里,包括了 OSSResolver 和 OSSService,它们都是用 @Injectable() 装饰器装饰的服务类。

OSSResolver: 用于处理与 OSS 相关的 GraphQL 请求和操作。

OSSService: 提供获取阿里云 OSS 签名的服务

编写oss.service

配置oss相关 config

arduino 复制代码
 const config = {
      accessKeyId: 'LTAI5t6D9W6ArgXXXX',
      accessKeySecret: '8YNGXLtXXTOIRXXXXXnt',
      bucket: 'healthflex',
      dir: 'images/',
    };

这是一个配置对象,其中包含了一些用于连接和访问阿里云 OSS(Object Storage Service)的必要信息。

accessKeyId:

该属性存储阿里云账户的 Access Key ID。

Access Key ID 用于标识阿里云账户,是访问和操作阿里云资源的身份标识。

accessKeySecret:

该属性存储阿里云账户的 Access Key Secret。

Access Key Secret 是与 Access Key ID 配套使用的密钥,用于对请求的签名和验证。

bucket:

bucket 是阿里云 OSS 中的存储桶,相当于一个命名空间,用于存储对象(文件)。

在这里,'healthflex' 是存储桶的名称,表示你要访问的特定存储桶。

dir:

dir 表示上传文件时的目录,用于在存储桶内组织对象的存储结构。

在这里,'images/' 表示上传的文件将存储在存储桶的 'images/' 目录下。

这个配置对象通常会被用于初始化阿里云 OSS 客户端,在使用 ali-oss 等相关库的 API 时,作为参数传递给初始化的函数。这样,阿里云 OSS 客户端就能够使用这些信息来与指定的存储桶进行通信,执行文件上传、下载等操作。

文件上传服务由于要返回查询结果,所以要定义返回的类型OSSType

定义dto,添加返回对象的类型

less 复制代码
import { Field, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class OSSType {
  @Field({ description: '过期时间' })
  expire: string;
  @Field({ description: '策略' })
  policy: string;
  @Field({ description: '签名' })
  signature: string;
  @Field({ description: 'key' })
  accessId: string;
  @Field({ description: 'host' })
  host: string;
}

以下是oss.service的完整代码

typescript 复制代码
import { Injectable } from '@nestjs/common';
import * as OSS from 'ali-oss';
import * as dayjs from 'dayjs';
import { OSSType } from './dto/oss.type';
@Injectable()
export class OSSService {
  //   获取签名
  async getSignature(): Promise<OSSType> {
    const config = {
      accessKeyId: 'LTAI5t8pPGHBcjAVASD3swxxD',
      accessKeySecret: 'kXkYy76asdasdcDQjdAXXXXXXXsaasdeasdfSlyM',
      bucket: 'healthflex',
      dir: 'images/',
    };
    const client = new OSS(config);

    const date = new Date();
    date.setDate(date.getDate() + 1);
    const policy = {
      expiration: date.toISOString(), // 请求有效期
      conditions: [
        ['content-length-range', 0, 1048576000], // 设置上传文件的大小限制
      ],
    };
    // bucket域名
    const host = `http://${config.bucket}.${
      (await client.getBucketLocation()).location
    }.aliyuncs.com`.toString();
    //签名
    const formData = await client.calculatePostSignature(policy);
    //返回参数
    const params = {
      expire: dayjs().add(1, 'days').unix().toString(),
      policy: formData.policy,
      signature: formData.Signature,
      accessId: formData.OSSAccessKeyId,
      host
    };
    return params;
  }
}

@Injectable(): 这是 NestJS 中的装饰器,用于标记这个类是一个可注入的服务(Service)。通过这个装饰器,NestJS 可以将这个类的实例注入到其他组件(如 Controller)中使用。

import * as OSS from 'ali-oss';: 使用 import * as 语法将整个 'ali-oss' 模块的所有导出内容放在一个名为 OSS 的对象中,以便在后续代码中使用。

async getSignature(): Promise: 这是一个异步方法,用于获取阿里云 OSS 的签名。返回一个 Promise,Promise 的值是一个类型为 OSSType 的对象。

const config = { ... };: 定义了用于创建 OSS 客户端的配置对象,包括阿里云的 Access Key、Bucket 名称和文件夹路径。

const client = new OSS(config);: 创建了阿里云 OSS 客户端实例。

const date = new Date(); ...: 创建了一个日期对象,然后计算了请求的有效期,并定义了上传文件的大小限制条件。

const formData = await client.calculatePostSignature(policy);: 使用 OSS 客户端计算了上传策略的签名,该签名将用于安全地将文件上传到 OSS。

const params = { ... };: 创建了一个包含签名等参数的对象,用于返回给调用方。

return params;: 返回包含签名等参数的对象,Promise 的结果。

这个服务类的目的是为前端应用提供获取阿里云 OSS 签名的功能,以便安全地上传文件到 OSS。

创建oss.resolver

typescript 复制代码
import { Query, Resolver } from '@nestjs/graphql';
import { OSSType } from './dto/oss.type';
import { OSSService } from './oss.service';
@Resolver()
export class OSSResolver {
  constructor(private readonly ossService: OSSService) {}
  @Query(() => OSSType, { description: '获取oss相关信息' })
  async getOSSInfo(): Promise<OSSType> {
    return await this.ossService.getSignature();
  }
}

@Resolver(): 这是 NestJS 中用于定义 GraphQL 解析器的装饰器。通过 @Resolver() 装饰器,可以将类标记为 GraphQL 解析器,并定义解析器中的查询和变更操作。

constructor(private readonly ossService: OSSService) {}: 解析器的构造函数接收一个参数 ossService,它是 OSSService 类的实例。这是通过 NestJS 的依赖注入系统注入的,用于在解析器中调用 OSSService 的功能。

@Query(() => OSSType, { description: '获取oss相关信息' }): 这是一个 GraphQL 查询操作的装饰器,表示下面的 getOSSInfo 方法是用于处理查询操作的。它的参数说明了该查询的返回类型是 OSSType,并提供了一个描述字符串。

async getOSSInfo(): Promise<OSSType>: 这是一个异步方法,用于处理 GraphQL 查询操作,返回一个 Promise,Promise 的值是一个类型为 OSSType 的对象。在该方法中,调用了 ossService.getSignature(),该方法是 OSSService 中的功能,用于获取阿里云 OSS 的签名信息。

总体来说,OSSResolver 类负责定义与 OSS 相关的 GraphQL 查询操作,它通过依赖注入系统使用 OSSService 提供的功能。在这个例子中,getOSSInfo 方法返回了获取的 OSS 签名信息,用于在前端应用中安全地上传文件到阿里云 OSS。

最终要记得在app.module.ts中引入oss.module

最终在graphql调试面板执行查询

markdown 复制代码
query getOSSInfo{
  getOSSInfo{
    expire
    policy
    signature
    accessId
    graphql
  }
}

总结

最终总结一下,对于服务端来说:

OSSModule(oss.module):

作用: OSSModule 是一个 NestJS 模块,用于组织和配置与 OSS 相关的功能。

构成:

导入模块:在示例中没有导入其他模块,但在实际应用中,可能需要导入其他相关的 NestJS 模块。

提供者:注册了 OSSResolver 和 OSSService,使它们在整个应用程序中可用。

OSSResolver(oss.resolver):

作用: OSSResolver 是一个 NestJS GraphQL 解析器,用于处理与 OSS 相关的 GraphQL 查询。

构成:

类装饰器:使用 @Resolver() 装饰器标记为一个 GraphQL 解析器类。

构造函数:接收 OSSService 的实例,通过依赖注入系统注入,用于在解析器中调用 OSS 相关服务。

查询操作:使用 @Query() 装饰器定义了查询操作 getOSSInfo,并指定了返回类型为 OSSType。

OSSService(oss.service):

作用: OSSService 是一个 NestJS 服务,提供了获取阿里云 OSS 签名的功能。

构成:

类装饰器:使用 @Injectable() 装饰器标记为一个可注入的服务类。

方法:包含了异步方法 getSignature,用于获取阿里云 OSS 的签名信息。

这三个部分一起构成了一个完整的后端服务的查询模块,用于处理前端应用发起的获取 OSS 签名的 GraphQL 查询。通过 NestJS 的依赖注入系统,OSSResolver 可以调用 OSSService 提供的功能,从而实现了模块内部的功能组合。前端应用可以通过调用 getOSSInfo 查询获取 OSS 相关信息,并使用这些信息在前端应用中安全地上传文件到阿里云 OSS。

相关推荐
花旗蜕变2 小时前
前端转 NestJS 全栈实践:从表单页面到微信业务系统
前端·typescript·nestjs
白帽攻防录1 天前
SRC 挖洞:Dgraph GraphQL 数据库注入深度复盘,CVE-2026-41328 两个请求拖走全库数据
网络安全·graphql
白帽攻防录4 天前
SRC 挖洞:GitLab GraphQL 指令绕过深度复盘,CVE-2026-19478 未授权删项目怎么打穿代码托管平台
网络·网络安全·gitlab·graphql
柒和远方6 天前
NestJS + TypeORM 学习笔记:语法和类型不绕了
postgresql·orm·nestjs
小二李12 天前
第15章 NestJS 项目部署
nestjs
前端踩bug工程师13 天前
nestjs 实现一对多,多对一,一对一在实现上的区别
nestjs
爱丶不疚18 天前
Electron:Module 与 Service 的职责边界与加载时序编排
前端·electron·nestjs
沐沐师1 个月前
Nest.js 微服务入门教程
微服务·nestjs
沐沐师1 个月前
Redis 入门教程
redis·nestjs
谷无姜1 个月前
QuizForge:在不停踩坑后的技术决策复盘
前端·nestjs