想整一个自动的图床,但是不想花钱买oss怎么办,那就白嫖一个

文摘   2024-11-22 23:32   北京  


关注公众号 前端界,回复“加群

加入我们一起学习,天天进步


本文作者@moment

原文链接:https://juejin.cn/post/7433243522555936779

很多时候我们都想建立一个自己的图床或者自己的博客,但是要想存储图片是一个比较麻烦的事情,需要搞一个 oss 来存储,但是又怕安全方面做不好被人刷流量。

这下发现了一个宝藏的云存储,可以免费使用包括 20GB 带宽、20GB 媒体存储、1000 个视频处理单元和 500 个扩展单元。具体:

  1. 无限请求

  2. 无限的图像转换

  3. 图像、视频和媒体管理功能

  4. 使用情况分析

  5. 20GB 带宽、20GB 媒体存储、1000 个视频处理单元和 500 个扩展单元

  6. 带有 72 小时 SLA 的电子邮件支持

更新详细的信息可以直接访问 imagekit[1]

在这里你可以看到我们上传的图片:

20241104124406

除了通过 api 上传之外你还可以手动上传。

如何在 NestJs 中使用

20241104124514

要想在 NestJs 中使用,首先我们需要点击到这里:

20241104124615

这些字段我们等会需要用到,它还提供了多种直接调用的方式,包括 React、Vue:

20241104124655

接下来我们就来看看如何在 NestJs 中使用这个 imagekit,首先它需要我们安装相关的包:

pnpm add imagekit

安装完成之后我们创建一个 controller:

import {
  Controller,
  Get,
  Post,
  UploadedFile,
  UseInterceptors,
from "@nestjs/common";
import {
  FileInterceptor,
  MulterFile,
from "@webundsoehne/nest-fastify-file-upload";

import { UploadService } from "./upload.service";

@Controller("upload")
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @Post("url")
  @UseInterceptors(FileInterceptor("file"))
  async convertImage(@UploadedFile() file: MulterFile) {
    console.log(file.originalname); // 文件原始名称
    console.log(file.buffer); // 文件内容的Buffer
    console.log(file.mimetype); // 文件的MIME类型

    const uploadResult = await this.uploadService.uploadImage(
      file.buffer,
      file.originalname
    );

    // 返回上传后的文件 URL
    return { url: uploadResult.url };
  }
}

定义完成 controller 之后我们要定义 service:

import { Injectable } from "@nestjs/common";
import ImageKit from "imagekit";
import * as crypto from "crypto";

@Injectable()
export class UploadService {
  private imageKit: ImageKit;
  private privateKey: string;

  constructor() {
    this.imageKit = new ImageKit({
      publicKey: "",
      privateKey: "",
      urlEndpoint: "",
    });
    this.privateKey = ""// 跟前面的privateKey一样
  }

  async uploadImage(file: Buffer, fileName: string): Promise<any> {
    // 生成文件的唯一哈希值
    const fileHash = this.generateFileHash(file);

    // 检查文件是否已存在
    const existingFile = await this.checkIfFileExists(fileHash);
    console.log(existingFile);

    if (existingFile) {
      return { url: existingFile.url }; // 返回已上传文件的URL
    }

    // 上传文件
    try {
      const response = await this.imageKit.upload({
        file, // 上传的文件内容
        fileName, // 文件名
        tags: [fileHash], // 将哈希值作为标签存储,便于后续查找
      });
      return response;
    } catch (error) {
      throw new Error(`Image upload failed: ${error.message}`);
    }
  }
}

就这样我们就生成了一个简单的文件上传的功能了,接下来我们通过 apifox 来测试一下相关的效果:

20241104130037

最终给我们返回了一个可以直接访问的链接:

20241104130105

如果你客户端直传的话就可以看下面的完整代码:

// controller

import {
  Controller,
  Get,
  Post,
  UploadedFile,
  UseInterceptors,
from "@nestjs/common";
import {
  FileInterceptor,
  MulterFile,
from "@webundsoehne/nest-fastify-file-upload";

import { UploadService } from "./upload.service";

@Controller("upload")
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @Post("url")
  @UseInterceptors(FileInterceptor("file"))
  async convertImage(@UploadedFile() file: MulterFile) {
    console.log(file.originalname); // 文件原始名称
    console.log(file.buffer); // 文件内容的Buffer
    console.log(file.mimetype); // 文件的MIME类型

    const uploadResult = await this.uploadService.uploadImage(
      file.buffer,
      file.originalname
    );

    // 返回上传后的文件 URL
    return { url: uploadResult.url };
  }

  @Get("signature")
  getUploadSignature() {
    return this.uploadService.generateUploadSignature();
  }
}

// Service
import { Injectable } from "@nestjs/common";
import ImageKit from "imagekit";
import * as crypto from "crypto";

@Injectable()
export class UploadService {
  private imageKit: ImageKit;
  private privateKey: string;

  constructor() {
    this.imageKit = new ImageKit({
      publicKey: "",
      privateKey: "",
      urlEndpoint: "",
    });
    this.privateKey = "";
  }

  private generateFileHash(file: Buffer): string {
    return crypto.createHash("md5").update(file).digest("hex");
  }

  async uploadImage(file: Buffer, fileName: string): Promise<any> {
    // 生成文件的唯一哈希值
    const fileHash = this.generateFileHash(file);

    // 检查文件是否已存在
    const existingFile = await this.checkIfFileExists(fileHash);
    console.log(existingFile);

    if (existingFile) {
      return { url: existingFile.url }; // 返回已上传文件的URL
    }

    // 上传文件
    try {
      const response = await this.imageKit.upload({
        file, // 上传的文件内容
        fileName, // 文件名
        tags: [fileHash], // 将哈希值作为标签存储,便于后续查找
      });
      return response;
    } catch (error) {
      throw new Error(`Image upload failed: ${error.message}`);
    }
  }

  private async checkIfFileExists(fileHash: string): Promise<any | null> {
    // 使用 ImageKit 的列表文件 API,根据文件哈希标签查找
    const files = await this.imageKit.listFiles({
      tags: fileHash,
      limit: 1// 只需要一个文件
    });

    console.log(files);

    return files.length > 0 ? files[0] : null;
  }

  generateUploadSignature() {
    const expire = Math.floor(Date.now() / 1000) + 30 * 60// 30分钟后过期
    const token = crypto.randomBytes(16).toString("hex");

    const signature = crypto
      .createHmac("sha1"this.privateKey)
      .update(token + expire)
      .digest("hex");

    return { signature, expire, token };
  }
}

这样子,我们的接口就编写完成了,这会我们就可以通过调用 signature 这个接口,然后它会返回一些 token 给我们,我们最终使用这些参数向固定的接口发起 post 请求,如下代码所示:

20241104130629

通过这种方式我们就可以将图片直接上传到 imagekit 了,并且不需要额外的将文件上传到我们自己的服务器了。

总结

有了 imagekit,再结合 supabase,vercel,足够让我们一个前端来上线一个前端的项目了。

最后再来提一些这两个开源项目,它们都是我们目前正在维护的开源项目:

  • 在线代码协同编辑器[2]

  • 前端脚手架 create-neat[3]


参考资料
[1]

https://imagekit.io/: https://imagekit.io/

[2]

https://github.com/xun082/online-edit-web: https://github.com/xun082/online-edit-web

[3]

https://github.com/xun082/create-neat: https://github.com/xun082/create-neat

最后

大家好,我是芝士,最近创建了一个低代码/前端工程化/高级前端面试交流群,欢迎加我微信,拉你进群,互相监督学习进步等!



关注福利,关注公众号后,在首页:

  • 回复「简历获取精选的简历模板

  • 回复「思维图」获取完整 JavaScript 相关思维图

  • 回复「电子书」可下载我整理的大量前端资源,包含面试、Vue实战项目、CSS和JavaScript电子书等。

  • 回复「Node」获取简历制作建议

最后不要忘了点个赞再走噢

前端界
高质量文章分享、实践干货、技术前沿、学习资料, 你感兴趣的都在前端界
 最新文章