1Panel + 七牛云 实现 上传
在七牛云建立并配置好空间后,在 ECS 做如下设置
1Panel 创建静态网站,配置 DNS 解析,配置 SSL 证书
配置前端页面
配置后端服务
1Panel 配置反向代理
前端页面 photos.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>照片上传</title>
<style>
body { font-family: Arial, sans-serif; max-width: 500px; margin: 0 auto; padding: 20px; }
button { background: #1890ff; color: white; border: none; padding: 10px 15px; border-radius: 4px; }
#preview { margin-top: 20px; }
img { max-width: 100px; margin: 5px; }
</style>
</head>
<body>
<h2>📸 请上传照片</h2>
<input type="file" id="fileInput" multiple accept="image/*">
<button onclick="upload()">一键上传</button>
<div id="preview"></div>
<script src="https://unpkg.com/qiniu-js@2.5.5/dist/qiniu.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script>
// 配置区
const bucket = "空间名";
const prefix = "photos"; // 空间下建立好 photos 目录
const domain = "空间域名";
// ✅ 从后端获取 Token 的异步函数
async function getUploadToken() {
try {
const response = await fetch('/qiniu/token_for_photos');
if (!response.ok) throw new Error('获取 Token For Photos 失败');
const { token } = await response.json();
return token;
} catch (err) {
alert('无法获取上传凭证,请稍后重试');
throw err;
}
}
// 显示预览
document.getElementById('fileInput').addEventListener('change', function(e) {
const preview = document.getElementById('preview');
preview.innerHTML = '';
Array.from(e.target.files).forEach(file => {
const img = document.createElement('img');
img.src = URL.createObjectURL(file);
preview.appendChild(img);
});
});
// 上传函数,使用后端 Token
async function upload() {
const files = document.getElementById('fileInput').files;
if (files.length === 0) return alert('请先选择照片!');
try {
// 从后端获取 Token
const uploadToken = await getUploadToken();
console.log("后端返回的Token:", uploadToken);
Array.from(files).forEach(file => {
const key = prefix + Date.now() + "-" + file.name;
const observable = qiniu.upload(file, key, uploadToken);
observable.subscribe({
complete: (res) => {
alert(`上传成功!链接:https://${domain}/${res.key}`);
},
error: (err) => {
console.error(err);
alert('上传失败:' + err.message);
}
});
});
} catch (err) {
console.error("上传流程错误:", err);
}
}
</script>
</body>
</html>后端服务 ****/services/photos.js:
// photos.js
const express = require('express');
const qiniu = require('qiniu');
const app = express();
const port = process.env.PHOTOS_PORT || 3001;
// 加载环境变量
require('dotenv').config();
// 七牛云认证
const mac = new qiniu.auth.digest.Mac(
process.env.QINIU_ACCESS_KEY,
process.env.QINIU_SECRET_KEY
);
// 生成上传凭证
scope: process.env.QINIU_BUCKET,
deadline: Math.floor(Date.now() / 1000) + 3600,
returnBody: '{"key":"$(key)"}'
};
app.get('/qiniu/token_for_photos', (req, res) => {
const options = {
scope: process.env.QINIU_BUCKET,
// 凭证有效期:1 小时
deadline: Math.floor(Date.now() / 1000) + 3600,
// 禁止覆盖已有文件
insertOnly: 1,
// 限制文件类型
mimeLimit: "image/*",
// 限制文件大小:最大 20 MB
fsizeLimit: 20 * 1024 * 1024,
// 强制返回上传后的文件路径
returnBody: '{"key":"$(key)"}'
};
const putPolicy = new qiniu.rs.PutPolicy(options);
const uploadToken = putPolicy.uploadToken(mac);
res.json({ token: uploadToken });
});
// 启动服务
app.listen(port, () => {
console.log(`Token 服务运行在端口 ${port}`);
});后端服务 ****/services/.env:
QINIU_ACCESS_KEY=七牛用户AK
QINIU_SECRET_KEY=七牛用户SK
QINIU_BUCKET=空间名
QINIU_DOMAIN=空间域名
PHOTOS_PORT=3001后端服务 /etc/systemd/system/qiniu-upload-photos.service:
[Unit]
Description=Qiniu Upload Photos Service
After=network.target
[Service]
User=root
WorkingDirectory=****/services
ExecStart=/usr/bin/node photos.js
Restart=always
EnvironmentFile=****/services/.env
[Install]
WantedBy=multi-user.target运行服务:
systemctl daemon-reload
systemctl start qiniu-upload-photos
systemctl enable qiniu-upload-photos网站中配置反代:

之后在源文中修改,以 https://aaa.bbb.ccc 为例:
location ^~ /qiniu/token_for_photos {
# 1. 校验 Origin(来源域名)
if ($http_origin !~* ^(https?://aaa\.bbb\.ccc)?$) {
return 403;
}
# 2. 校验 Referer(来源页面)
if ($http_referer !~* ^https?://aaa\.bbb\.ccc/.*$) {
return 403;
}
proxy_pass http://127.0.0.1:3001;
....
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 黑凤梨 - 生信极客小栈
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果