关注公众号 前端界,回复“加群”
加入我们一起学习,天天进步
本文作者@moment
原文链接:https://juejin.cn/post/7433243522555936779
很多时候我们都想建立一个自己的图床或者自己的博客,但是要想存储图片是一个比较麻烦的事情,需要搞一个 oss 来存储,但是又怕安全方面做不好被人刷流量。
这下发现了一个宝藏的云存储,可以免费使用包括 20GB 带宽、20GB 媒体存储、1000 个视频处理单元和 500 个扩展单元。具体:
无限请求
无限的图像转换
图像、视频和媒体管理功能
使用情况分析
20GB 带宽、20GB 媒体存储、1000 个视频处理单元和 500 个扩展单元
带有 72 小时 SLA 的电子邮件支持
更新详细的信息可以直接访问 imagekit[1]
在这里你可以看到我们上传的图片:
除了通过 api 上传之外你还可以手动上传。
如何在 NestJs 中使用
要想在 NestJs 中使用,首先我们需要点击到这里:
这些字段我们等会需要用到,它还提供了多种直接调用的方式,包括 React、Vue:
接下来我们就来看看如何在 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 来测试一下相关的效果:
最终给我们返回了一个可以直接访问的链接:
如果你客户端直传的话就可以看下面的完整代码:
// 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 请求,如下代码所示:
通过这种方式我们就可以将图片直接上传到 imagekit 了,并且不需要额外的将文件上传到我们自己的服务器了。
总结
有了 imagekit,再结合 supabase,vercel,足够让我们一个前端来上线一个前端的项目了。
最后再来提一些这两个开源项目,它们都是我们目前正在维护的开源项目:
在线代码协同编辑器[2]
前端脚手架 create-neat[3]
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」获取简历制作建议
最后不要忘了点个赞再走噢