avatar-uploader/
├── public/
│ ├── index.html # 前端页面
│ ├── style.css # 样式文件
│ └── script.js # 前端逻辑
├── uploads/ # 存储上传的头像(需手动创建)
├── server.js # Node.js后端服务
└── package.json # 项目配置
public/index.html)<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">AE头像上传</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h2>上传AE头像</h2>
<div class="avatar-preview">
<img id="avatar-preview" src="default-avatar.png" alt="头像预览">
</div>
<input type="file" id="avatar-input" accept="image/*">
<button id="upload-btn">上传头像</button>
<div id="message"></div>
</div>
<script src="script.js"></script>
</body>
</html>
public/style.css)body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #f5f5f5;
}
.container {
text-align: center;
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}
.avatar-preview {
width: 150px;
height: 150px;
margin: 0 auto 20px;
border-radius: 50%;
overflow: hidden;
border: 3px solid #ddd;
}
.avatar-preview img {
width: 100%;
height: 100%;
object-fit: cover;
}
#avatar-input {
display: none;
}
#upload-btn {
padding: 10px 20px;
background: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin-top: 10px;
}
#message {
margin-top: 15px;
color: #666;
}
public/script.js)document.getElementById('upload-btn').addEventListener('click', () => {
document.getElementById('avatar-input').click();
});
document.getElementById('avatar-input').addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
document.getElementById('avatar-preview').src = e.target.result;
};
reader.readAsDataURL(file);
}
});
document.getElementById('upload-btn').addEventListener('click', async () => {
const fileInput = document.getElementById('avatar-input');
const file = fileInput.files[0];
if (!file) {
document.getElementById('message').textContent = '请选择头像文件!';
return;
}
const formData = new FormData();
formData.append('avatar', file);
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.success) {
document.getElementById('message').textContent = `头像上传成功!路径: ${result.path}`;
} else {
document.getElementById('message').textContent = `上传失败: ${result.error}`;
}
} catch (error) {
document.getElementById('message').textContent = '服务器错误!';
}
});
server.js)const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const app = express();
const port = 3000;
// 确保uploads目录存在
const uploadDir = 'uploads';
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir);
}
// 配置文件存储
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
// 生成唯一文件名
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits: { fileSize: 2 * 1024 * 1024 }, // 2MB限制
fileFilter: (req, file, cb) => {
// 只允许图片文件
const allowedTypes = /jpeg|jpg|png|gif/;
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = allowedTypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb(new Error('只允许上传图片文件!'));
}
}
});
// 静态文件服务
app.use(express.static('public'));
app.use('/uploads', express.static('uploads'));
// 头像上传接口
app.post('/upload', upload.single('avatar'), (req, res) => {
if (!req.file) {
return res.status(400).json({
success: false,
error: '未选择文件或文件类型错误!'
});
}
const filePath = `/uploads/${req.file.filename}`;
res.json({
success: true,
path: filePath
});
});
// 错误处理
app.use((err, req, res, next) => {
if (err instanceof multer.MulterError) {
res.status(400).json({ success: false, error: err.message });
} else if (err) {
res.status(500).json({ success: false, error: err.message });
}
});
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});
package.json){
"name": "ae-avatar-uploader",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.2",
"multer": "^1.4.5-lts.1"
}
}
安装依赖:

npm install
创建目录:
mkdir uploads
启动服务:

npm start
访问页面:
打开浏览器访问 http://localhost:3000
生产环境加固:
部署建议:
uploads目录源码打包下载:点击下载完整项目源码(示例链接,需替换为实际仓库地址)
