personal/api/server.js

111 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const nodemailer = require('nodemailer');
const dotenv = require('dotenv');
// 加载环境变量
dotenv.config();
const app = express();
const port = process.env.PORT || 3001;
// 中间件
app.use(cors({
origin: '*', // 允许所有来源访问
methods: ['GET', 'POST', 'OPTIONS'], // 允许的HTTP方法
allowedHeaders: ['Content-Type', 'Authorization'], // 允许的请求头
credentials: true // 允许发送凭证
}));
app.use(bodyParser.json());
// 处理OPTIONS预检请求
app.options('*', (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Max-Age', '86400'); // 24小时
res.sendStatus(204);
});
// 创建Nodemailer传输器
const transporter = nodemailer.createTransport({
service: process.env.EMAIL_SERVICE || 'smtp', // 邮件服务商,例如:'gmail', 'qq', '163'等
host: process.env.EMAIL_HOST || 'smtp.163.com', // SMTP服务器
port: parseInt(process.env.EMAIL_PORT || '587'),
secure: process.env.EMAIL_SECURE === 'true', // true for 465, false for other ports
auth: {
user: process.env.EMAIL_USER || '', // 发送方邮箱
pass: process.env.EMAIL_PASS || '', // 授权码或密码
},
});
// 存储IP地址最后发送邮件的时间
const lastEmailSentTime = new Map();
// 速率限制中间件 - 60秒内只能发送一封邮件
const rateLimitMiddleware = (req, res, next) => {
const ip = req.ip || req.connection.remoteAddress;
const currentTime = Date.now();
const lastTime = lastEmailSentTime.get(ip) || 0;
const timeDiff = currentTime - lastTime;
// 如果距离上次发送不足60秒则拒绝请求
if (lastTime && timeDiff < 60000) {
const remainingTime = Math.ceil((60000 - timeDiff) / 1000);
return res.status(429).json({
error: `请求过于频繁,请在${remainingTime}秒后再试`,
remainingTime
});
}
// 更新最后发送时间并继续处理请求
lastEmailSentTime.set(ip, currentTime);
next();
};
// 邮件发送接口
app.post('/api/send-email', rateLimitMiddleware, async (req, res) => {
const { name, email, subject, message } = req.body;
if (!name || !email || !message) {
return res.status(400).json({ error: '请填写所有必填字段' });
}
try {
// 邮件选项
const mailOptions = {
from: `"个人网站联系表单" <${process.env.EMAIL_USER}>`,
to: process.env.EMAIL_RECIPIENT || process.env.EMAIL_USER, // 接收方邮箱
subject: subject ? `新的联系表单消息: ${subject}` : '新的联系表单消息',
html: `
<h3>您有一条新的联系表单消息</h3>
<p><strong>姓名:</strong> ${name}</p>
<p><strong>邮箱:</strong> ${email}</p>
<p><strong>主题:</strong> ${subject || '无'}</p>
<p><strong>消息:</strong></p>
<p>${message.replace(/\n/g, '<br>')}</p>
`,
// 回复选项,回复时会发送到表单提交者的邮箱
replyTo: email
};
// 发送邮件
await transporter.sendMail(mailOptions);
return res.status(200).json({ success: true, message: '邮件已成功发送' });
} catch (error) {
console.error('发送邮件时出错:', error);
return res.status(500).json({ error: '发送邮件失败,请稍后再试' });
}
});
// 测试路由
app.get('/api/test', (req, res) => {
res.json({ message: 'API服务器运行正常' });
});
// 启动服务器
app.listen(port, () => {
console.log(`邮件服务API正在端口 ${port} 上运行`);
});