自己开发一个图床接口——基于 NodeJS.
自己开发一个图床接口——基于 NodeJS.
前言
最近买了一堆服务器不知道要用来干什么…看到某乎上的回答,便准备搭建一个图床。但觉得这些现成的图床程序有些「花里胡哨」,于是便决定自己基于 NodeJS 开发一个图床接口自用。
为什么不用 OSS / COS?
阿里云 OSS, 腾讯云 COS 都属于对象存储。它的计费分为两部分:存储计费和流量计费。存储计费十分简单,并且都相应提供了存储包,十分划算。但是在流量计费上就有些复杂了,如果你的对象存储被人死刷流量,一夜破产都有可能。且我个人使用的阿里云 OSS 并没有频次控制功能,因此我选择购买一台服务器解决这个问题,因为它能通过一系列配置预防此类 CC 攻击。
如何实现?
我们可以将这个图床接口看作这些「简单」的动作。
客户端发送 POST 请求->反向代理(可选)->Express->反向代理(可选)->返回图床JSON数据。
而对于后端的 NodeJS,我们大概需要对传入的图片做这些处理。
- 获取文件名的 MD5 值
- 获取传入图片的后缀名
- 将图片以文件名 “图片文件名MD5 + 传入图片后缀名” 的形式进行存储
- 向客户端返回 JSON (包含 status 和图片链接)
知道了这些,我们就可以开始愉快的开发了。
开发
首先我们需要引入 express 框架,并创建一个应用。express 需要通过 npm 进行安装。
const express = require(‘express’);
const app = express();
之后在这基础上,创建一个 server 并监听 4000 端口。
var server = app.listen(4000, ‘127.0.0.1’, function(){
var host = server.address().address;
var port = server.address().port;
console.log(“Server running at http://%s:%s”, host, port);
})
之后,我们便可以开始解决 POST 文件的处理了。
首先,我们需要引入和配置这些中间件和模块,它们各自的作用已经写在注释了。
// 工具库 - lodash
const _ = require('lodash');
// assert - 测试是否为真值
const { ok } = require('assert');
// crypto - 用于获取文件名 MD5 值
const crypto = require('crypto');
// path - 用于获取文件拓展名
var path=require('path');
// 使用 express-fileupload 中间件
const fileUpload = require('express-fileupload');
app.use(fileUpload({
createParentPath: true
}));
// 处理跨域问题 - cors 模块
const cors = require('cors');
app.use(cors());
// 解析 POST 数据
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// 使用 morgan 中间件 - 输出请求详细信息
const morgan = require('morgan');
app.use(morgan('dev'));
接下来,便可以编写接收和处理数据的代码了。
app.post('/api/post', async (req, res) => {
try {
// 如果没有文件被上传,则返回以下 JSON 数据
if(!req.files) {
res.send({
status: "No file uploaded",
link: "undefined"
})
}
else{
let avatar = req.files.avatar; // 声明字段名为 avatar 的图片数据为 avatar 变量
let md5 = crypto.createHash('md5').update(avatar.name).digest('hex'); // 取 avatar 文件名的 MD5 值
avatar.mv('./uploads/' + md5 + path.extname(avatar.name)); // 存储(移动)图片到 uploads 文件夹,文件名为 avatar 文件名 MD5 + 文件拓展名
// 发送以下 JSON 数据
res.send({
status: "ok",
link: "https://example.com/uploads/" + md5 + path.extname(avatar.name)
});
}
}
// 如果上传出现错误,则返回 HTTP 500.
catch (err) {
res.status(500).send(err);
}
})
最后,你可以尝试运行 app.js 然后使用 Postman 来测试它。
node app.js
进阶操作 (外网服务配置 + 持久化)
如果要在公网上进行使用,我们或许需要配置 Nginx 反向代理到 express. 当然,你也可以直接将 Express 暴露在公网上。
以下是我的反向代理配置,从宝塔面板抄来的。
location ~* \.(php|jsp|cgi|asp|aspx)$
{
proxy_pass http://localhost:4000;
proxy_set_header Host localhost;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
}
location /api/post
{
proxy_pass http://localhost:4000;
proxy_set_header Host localhost;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;
#Set Nginx Cache
add_header Cache-Control no-cache;
expires 12h;
}
同时为了方便,我将图片存储在了站点根目录的 uploads 文件夹中。当然,你也需要更改 app.js 中的相应代码。
avatar.mv(‘/usr/local/openresty/nginx/html/uploads/’ + md5 + path.extname(avatar.name));
为了持久化运行,你也可以使用 forever 守护此进程。
npm install -g forever
forever start app.js
使用(uPic)
既然都开发好了…我们怎么能不对其进行应用呢(
这里我使用了 uPic 这个开源工具,你可以查看这篇文章进行了解:「uPic:支持自定义,一款免费而强大的Mac图床客户端」
你可以参考下图,对你的 uPic 进行配置。