Search K
Appearance
Appearance
📊 SEO元描述:2024年最新Node.js POST请求处理教程,详解表单数据处理、JSON解析、文件上传。包含完整代码示例,适合Web开发者快速掌握数据处理技术。
核心关键词:Node.js POST请求2024、表单数据处理、JSON数据解析、Node.js文件上传、HTTP请求体处理
长尾关键词:Node.js怎么处理POST数据、表单数据解析方法、Node.js文件上传教程、JSON数据处理技巧、HTTP请求体大小限制
通过本节Node.js处理POST请求教程,你将系统性掌握:
POST请求是什么?这是Web开发中的核心概念。POST请求是HTTP协议中用于向服务器发送数据的方法,也是Web应用交互的重要基础。
💡 设计理念:POST请求适合传输敏感数据、大量数据和复杂数据结构
让我们从最基本的POST请求处理开始:
// 🎉 POST请求基础处理示例
const http = require('http');
const url = require('url');
// 解析请求体的工具函数
function parseRequestBody(req) {
return new Promise((resolve, reject) => {
let body = '';
let totalSize = 0;
const maxSize = 1024 * 1024; // 1MB限制
req.on('data', chunk => {
totalSize += chunk.length;
// 检查请求体大小
if (totalSize > maxSize) {
reject(new Error('Request body too large'));
return;
}
body += chunk.toString();
});
req.on('end', () => {
resolve(body);
});
req.on('error', reject);
});
}
const server = http.createServer(async (req, res) => {
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname;
const method = req.method;
// 设置CORS头
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
if (method === 'POST') {
try {
const body = await parseRequestBody(req);
const contentType = req.headers['content-type'] || '';
console.log('POST请求详情:');
console.log('路径:', pathname);
console.log('Content-Type:', contentType);
console.log('请求体长度:', body.length);
console.log('请求体内容:', body);
// 响应处理结果
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({
message: 'POST请求处理成功',
method,
pathname,
contentType,
bodyLength: body.length,
body: body.substring(0, 200) + (body.length > 200 ? '...' : ''),
timestamp: new Date().toISOString()
}, null, 2));
} catch (error) {
console.error('POST请求处理错误:', error.message);
if (error.message === 'Request body too large') {
res.writeHead(413, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Payload Too Large',
message: '请求体大小超过限制'
}));
} else {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Bad Request',
message: '请求处理失败'
}));
}
}
} else if (method === 'GET' && pathname === '/') {
// 提供测试页面
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>POST请求测试</title>
<meta charset="utf-8">
</head>
<body>
<h1>POST请求测试页面</h1>
<h2>表单测试</h2>
<form action="/form" method="POST">
<p>
<label>姓名: <input type="text" name="name" required></label>
</p>
<p>
<label>邮箱: <input type="email" name="email" required></label>
</p>
<p>
<label>年龄: <input type="number" name="age"></label>
</p>
<p>
<label>备注: <textarea name="note"></textarea></label>
</p>
<p>
<button type="submit">提交表单</button>
</p>
</form>
<h2>JSON测试</h2>
<button onclick="sendJSON()">发送JSON数据</button>
<script>
function sendJSON() {
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Alice',
email: 'alice@example.com',
age: 25,
hobbies: ['reading', 'coding']
})
})
.then(response => response.json())
.then(data => {
alert('JSON响应: ' + JSON.stringify(data, null, 2));
})
.catch(error => {
alert('错误: ' + error.message);
});
}
</script>
</body>
</html>
`);
} else {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Not Found',
message: '页面不存在'
}));
}
});
server.listen(3000, () => {
console.log('POST请求处理服务器启动:http://localhost:3000');
console.log('测试页面:http://localhost:3000');
});// 🔍 表单数据处理详解
const http = require('http');
const url = require('url');
const querystring = require('querystring');
// 表单数据解析器
class FormDataParser {
static parse(body, contentType) {
if (contentType.includes('application/x-www-form-urlencoded')) {
return querystring.parse(body);
}
throw new Error('Unsupported content type');
}
static validate(data, rules) {
const errors = [];
for (const [field, rule] of Object.entries(rules)) {
const value = data[field];
if (rule.required && (!value || value.trim() === '')) {
errors.push(`${field} 是必需字段`);
continue;
}
if (value && rule.type === 'email' && !this.isValidEmail(value)) {
errors.push(`${field} 必须是有效的邮箱地址`);
}
if (value && rule.type === 'number' && isNaN(Number(value))) {
errors.push(`${field} 必须是数字`);
}
if (value && rule.minLength && value.length < rule.minLength) {
errors.push(`${field} 长度不能少于 ${rule.minLength} 个字符`);
}
if (value && rule.maxLength && value.length > rule.maxLength) {
errors.push(`${field} 长度不能超过 ${rule.maxLength} 个字符`);
}
}
return errors;
}
static isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
static sanitize(data) {
const sanitized = {};
for (const [key, value] of Object.entries(data)) {
if (typeof value === 'string') {
// 去除首尾空格,转义HTML字符
sanitized[key] = value.trim()
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
} else {
sanitized[key] = value;
}
}
return sanitized;
}
}
const server = http.createServer(async (req, res) => {
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname;
const method = req.method;
if (method === 'POST' && pathname === '/form') {
try {
// 解析请求体
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
await new Promise((resolve, reject) => {
req.on('end', resolve);
req.on('error', reject);
});
const contentType = req.headers['content-type'] || '';
console.log('表单数据处理:');
console.log('Content-Type:', contentType);
console.log('原始数据:', body);
// 解析表单数据
const formData = FormDataParser.parse(body, contentType);
console.log('解析后数据:', formData);
// 定义验证规则
const validationRules = {
name: { required: true, minLength: 2, maxLength: 50 },
email: { required: true, type: 'email' },
age: { type: 'number' },
note: { maxLength: 500 }
};
// 验证数据
const validationErrors = FormDataParser.validate(formData, validationRules);
if (validationErrors.length > 0) {
res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({
error: 'Validation Failed',
message: '数据验证失败',
details: validationErrors
}, null, 2));
return;
}
// 清理数据
const sanitizedData = FormDataParser.sanitize(formData);
// 模拟保存到数据库
const savedUser = {
id: Date.now(),
...sanitizedData,
createdAt: new Date().toISOString()
};
console.log('保存的用户数据:', savedUser);
// 响应成功
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({
message: '表单提交成功',
data: savedUser
}, null, 2));
} catch (error) {
console.error('表单处理错误:', error);
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Internal Server Error',
message: '表单处理失败'
}));
}
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
server.listen(3000, () => {
console.log('表单数据处理服务器启动:http://localhost:3000');
});表单数据处理要点:
// 🚀 JSON数据解析处理
const http = require('http');
const url = require('url');
// JSON数据处理器
class JSONDataProcessor {
static async parseJSON(req) {
return new Promise((resolve, reject) => {
let body = '';
const maxSize = 1024 * 1024; // 1MB限制
let totalSize = 0;
req.on('data', chunk => {
totalSize += chunk.length;
if (totalSize > maxSize) {
reject(new Error('JSON payload too large'));
return;
}
body += chunk.toString();
});
req.on('end', () => {
try {
const jsonData = JSON.parse(body);
resolve(jsonData);
} catch (error) {
reject(new Error('Invalid JSON format'));
}
});
req.on('error', reject);
});
}
static validateJSON(data, schema) {
const errors = [];
// 检查必需字段
if (schema.required) {
for (const field of schema.required) {
if (!(field in data) || data[field] === null || data[field] === undefined) {
errors.push(`缺少必需字段: ${field}`);
}
}
}
// 检查字段类型和约束
if (schema.properties) {
for (const [field, rules] of Object.entries(schema.properties)) {
const value = data[field];
if (value !== undefined && value !== null) {
// 类型检查
if (rules.type && typeof value !== rules.type) {
errors.push(`字段 ${field} 类型错误,期望 ${rules.type},实际 ${typeof value}`);
}
// 字符串长度检查
if (rules.type === 'string') {
if (rules.minLength && value.length < rules.minLength) {
errors.push(`字段 ${field} 长度不能少于 ${rules.minLength}`);
}
if (rules.maxLength && value.length > rules.maxLength) {
errors.push(`字段 ${field} 长度不能超过 ${rules.maxLength}`);
}
if (rules.pattern && !new RegExp(rules.pattern).test(value)) {
errors.push(`字段 ${field} 格式不正确`);
}
}
// 数字范围检查
if (rules.type === 'number') {
if (rules.minimum && value < rules.minimum) {
errors.push(`字段 ${field} 不能小于 ${rules.minimum}`);
}
if (rules.maximum && value > rules.maximum) {
errors.push(`字段 ${field} 不能大于 ${rules.maximum}`);
}
}
// 数组检查
if (rules.type === 'object' && Array.isArray(value)) {
if (rules.minItems && value.length < rules.minItems) {
errors.push(`字段 ${field} 至少需要 ${rules.minItems} 个元素`);
}
if (rules.maxItems && value.length > rules.maxItems) {
errors.push(`字段 ${field} 最多允许 ${rules.maxItems} 个元素`);
}
}
}
}
}
return errors;
}
static sanitizeJSON(data) {
if (typeof data === 'string') {
return data.trim();
}
if (Array.isArray(data)) {
return data.map(item => this.sanitizeJSON(item));
}
if (typeof data === 'object' && data !== null) {
const sanitized = {};
for (const [key, value] of Object.entries(data)) {
sanitized[key] = this.sanitizeJSON(value);
}
return sanitized;
}
return data;
}
}
const server = http.createServer(async (req, res) => {
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname;
const method = req.method;
// 设置CORS
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
if (method === 'POST' && pathname === '/api/users') {
try {
const contentType = req.headers['content-type'] || '';
if (!contentType.includes('application/json')) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Invalid Content-Type',
message: '请求必须是 application/json 格式'
}));
return;
}
// 解析JSON数据
const jsonData = await JSONDataProcessor.parseJSON(req);
console.log('接收到的JSON数据:', jsonData);
// 定义JSON Schema
const userSchema = {
required: ['name', 'email'],
properties: {
name: {
type: 'string',
minLength: 2,
maxLength: 50
},
email: {
type: 'string',
pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$'
},
age: {
type: 'number',
minimum: 0,
maximum: 150
},
hobbies: {
type: 'object', // Array is object in typeof
minItems: 0,
maxItems: 10
},
address: {
type: 'object',
properties: {
street: { type: 'string' },
city: { type: 'string' },
zipCode: { type: 'string' }
}
}
}
};
// 验证JSON数据
const validationErrors = JSONDataProcessor.validateJSON(jsonData, userSchema);
if (validationErrors.length > 0) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Validation Failed',
message: 'JSON数据验证失败',
details: validationErrors
}, null, 2));
return;
}
// 清理数据
const sanitizedData = JSONDataProcessor.sanitizeJSON(jsonData);
// 模拟保存用户
const newUser = {
id: Date.now(),
...sanitizedData,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
console.log('创建的用户:', newUser);
// 响应成功
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
message: '用户创建成功',
data: newUser
}, null, 2));
} catch (error) {
console.error('JSON处理错误:', error.message);
let statusCode = 500;
let errorMessage = '服务器内部错误';
if (error.message === 'Invalid JSON format') {
statusCode = 400;
errorMessage = 'JSON格式错误';
} else if (error.message === 'JSON payload too large') {
statusCode = 413;
errorMessage = 'JSON数据过大';
}
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'JSON Processing Error',
message: errorMessage
}));
}
} else if (method === 'GET' && pathname === '/') {
// 提供JSON测试页面
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>JSON数据处理测试</title>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.container { max-width: 800px; }
textarea { width: 100%; height: 200px; font-family: monospace; }
button { padding: 10px 20px; margin: 10px 0; }
.result { background: #f5f5f5; padding: 15px; margin: 10px 0; border-radius: 5px; }
</style>
</head>
<body>
<div class="container">
<h1>JSON数据处理测试</h1>
<h2>发送JSON数据</h2>
<textarea id="jsonInput" placeholder="输入JSON数据...">{
"name": "Alice",
"email": "alice@example.com",
"age": 25,
"hobbies": ["reading", "coding", "traveling"],
"address": {
"street": "123 Main St",
"city": "New York",
"zipCode": "10001"
}
}</textarea>
<br>
<button onclick="sendJSON()">发送JSON数据</button>
<button onclick="sendInvalidJSON()">发送无效JSON</button>
<div id="result" class="result" style="display: none;"></div>
</div>
<script>
function sendJSON() {
const jsonText = document.getElementById('jsonInput').value;
try {
const jsonData = JSON.parse(jsonText);
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(jsonData)
})
.then(response => response.json())
.then(data => {
showResult('成功', JSON.stringify(data, null, 2));
})
.catch(error => {
showResult('错误', error.message);
});
} catch (error) {
showResult('JSON格式错误', error.message);
}
}
function sendInvalidJSON() {
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: '{"name": "Alice", "email": invalid}'
})
.then(response => response.json())
.then(data => {
showResult('响应', JSON.stringify(data, null, 2));
})
.catch(error => {
showResult('错误', error.message);
});
}
function showResult(title, content) {
const resultDiv = document.getElementById('result');
resultDiv.innerHTML = '<h3>' + title + '</h3><pre>' + content + '</pre>';
resultDiv.style.display = 'block';
}
</script>
</body>
</html>
`);
} else {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Not Found',
message: '请求的资源不存在'
}));
}
});
server.listen(3000, () => {
console.log('JSON数据处理服务器启动:http://localhost:3000');
console.log('测试页面:http://localhost:3000');
console.log('API端点:POST http://localhost:3000/api/users');
});JSON数据处理要点:
// 📁 文件上传处理实现
const http = require('http');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
// 简单的multipart解析器
class MultipartParser {
static parse(body, boundary) {
const parts = [];
const boundaryBuffer = Buffer.from('--' + boundary);
const endBoundaryBuffer = Buffer.from('--' + boundary + '--');
let start = 0;
let end = body.indexOf(boundaryBuffer, start);
while (end !== -1) {
if (start > 0) {
const partData = body.slice(start, end);
const part = this.parsePart(partData);
if (part) {
parts.push(part);
}
}
start = end + boundaryBuffer.length;
end = body.indexOf(boundaryBuffer, start);
}
return parts;
}
static parsePart(partBuffer) {
const headerEndIndex = partBuffer.indexOf('\r\n\r\n');
if (headerEndIndex === -1) return null;
const headerSection = partBuffer.slice(0, headerEndIndex).toString();
const bodySection = partBuffer.slice(headerEndIndex + 4);
// 解析Content-Disposition头
const dispositionMatch = headerSection.match(/Content-Disposition:\s*form-data;\s*name="([^"]+)"(?:;\s*filename="([^"]+)")?/i);
if (!dispositionMatch) return null;
const fieldName = dispositionMatch[1];
const filename = dispositionMatch[2];
// 解析Content-Type头
const contentTypeMatch = headerSection.match(/Content-Type:\s*([^\r\n]+)/i);
const contentType = contentTypeMatch ? contentTypeMatch[1] : 'text/plain';
return {
fieldName,
filename,
contentType,
data: bodySection.slice(0, -2) // 移除结尾的\r\n
};
}
}
// 文件上传处理器
class FileUploadHandler {
constructor(uploadDir = './uploads') {
this.uploadDir = uploadDir;
this.ensureUploadDir();
}
ensureUploadDir() {
if (!fs.existsSync(this.uploadDir)) {
fs.mkdirSync(this.uploadDir, { recursive: true });
}
}
async handleUpload(req) {
return new Promise((resolve, reject) => {
let body = Buffer.alloc(0);
const maxSize = 10 * 1024 * 1024; // 10MB限制
let totalSize = 0;
req.on('data', chunk => {
totalSize += chunk.length;
if (totalSize > maxSize) {
reject(new Error('File too large'));
return;
}
body = Buffer.concat([body, chunk]);
});
req.on('end', () => {
try {
const contentType = req.headers['content-type'] || '';
const boundaryMatch = contentType.match(/boundary=(.+)$/);
if (!boundaryMatch) {
reject(new Error('No boundary found'));
return;
}
const boundary = boundaryMatch[1];
const parts = MultipartParser.parse(body, boundary);
const result = {
fields: {},
files: []
};
for (const part of parts) {
if (part.filename) {
// 处理文件
const file = this.saveFile(part);
result.files.push(file);
} else {
// 处理表单字段
result.fields[part.fieldName] = part.data.toString();
}
}
resolve(result);
} catch (error) {
reject(error);
}
});
req.on('error', reject);
});
}
saveFile(part) {
// 生成唯一文件名
const ext = path.extname(part.filename);
const basename = path.basename(part.filename, ext);
const uniqueName = `${basename}_${Date.now()}_${crypto.randomBytes(4).toString('hex')}${ext}`;
const filePath = path.join(this.uploadDir, uniqueName);
// 保存文件
fs.writeFileSync(filePath, part.data);
return {
fieldName: part.fieldName,
originalName: part.filename,
filename: uniqueName,
path: filePath,
size: part.data.length,
contentType: part.contentType
};
}
validateFile(file, options = {}) {
const errors = [];
// 检查文件大小
if (options.maxSize && file.size > options.maxSize) {
errors.push(`文件大小超过限制 (${options.maxSize} bytes)`);
}
// 检查文件类型
if (options.allowedTypes && !options.allowedTypes.includes(file.contentType)) {
errors.push(`不支持的文件类型: ${file.contentType}`);
}
// 检查文件扩展名
if (options.allowedExtensions) {
const ext = path.extname(file.originalName).toLowerCase();
if (!options.allowedExtensions.includes(ext)) {
errors.push(`不支持的文件扩展名: ${ext}`);
}
}
return errors;
}
}
const uploadHandler = new FileUploadHandler('./uploads');
const server = http.createServer(async (req, res) => {
const { method, url: reqUrl } = req;
if (method === 'POST' && reqUrl === '/upload') {
try {
console.log('处理文件上传请求...');
const result = await uploadHandler.handleUpload(req);
console.log('上传结果:', result);
// 验证上传的文件
const validationOptions = {
maxSize: 5 * 1024 * 1024, // 5MB
allowedTypes: ['image/jpeg', 'image/png', 'image/gif', 'text/plain', 'application/pdf'],
allowedExtensions: ['.jpg', '.jpeg', '.png', '.gif', '.txt', '.pdf']
};
const validatedFiles = [];
const validationErrors = [];
for (const file of result.files) {
const errors = uploadHandler.validateFile(file, validationOptions);
if (errors.length > 0) {
validationErrors.push({
file: file.originalName,
errors
});
// 删除无效文件
fs.unlinkSync(file.path);
} else {
validatedFiles.push(file);
}
}
if (validationErrors.length > 0) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'File Validation Failed',
message: '文件验证失败',
details: validationErrors
}, null, 2));
return;
}
// 响应成功
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
message: '文件上传成功',
fields: result.fields,
files: validatedFiles.map(file => ({
fieldName: file.fieldName,
originalName: file.originalName,
filename: file.filename,
size: file.size,
contentType: file.contentType
}))
}, null, 2));
} catch (error) {
console.error('文件上传错误:', error.message);
let statusCode = 500;
let errorMessage = '文件上传失败';
if (error.message === 'File too large') {
statusCode = 413;
errorMessage = '文件过大';
} else if (error.message === 'No boundary found') {
statusCode = 400;
errorMessage = '无效的multipart请求';
}
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Upload Error',
message: errorMessage
}));
}
} else if (method === 'GET' && reqUrl === '/') {
// 提供文件上传测试页面
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>文件上传测试</title>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.upload-form { border: 2px dashed #ccc; padding: 20px; margin: 20px 0; }
.file-input { margin: 10px 0; }
.result { background: #f5f5f5; padding: 15px; margin: 10px 0; border-radius: 5px; }
</style>
</head>
<body>
<h1>文件上传测试</h1>
<div class="upload-form">
<h2>选择文件上传</h2>
<form action="/upload" method="POST" enctype="multipart/form-data">
<div class="file-input">
<label>用户名: <input type="text" name="username" required></label>
</div>
<div class="file-input">
<label>描述: <textarea name="description"></textarea></label>
</div>
<div class="file-input">
<label>选择文件: <input type="file" name="file" multiple></label>
</div>
<div class="file-input">
<button type="submit">上传文件</button>
</div>
</form>
</div>
<div class="upload-form">
<h2>拖拽上传 (JavaScript)</h2>
<div id="dropZone" style="border: 2px dashed #ccc; padding: 40px; text-align: center;">
拖拽文件到这里或点击选择文件
<input type="file" id="fileInput" multiple style="display: none;">
</div>
<div id="uploadResult" class="result" style="display: none;"></div>
</div>
<script>
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const uploadResult = document.getElementById('uploadResult');
dropZone.addEventListener('click', () => fileInput.click());
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.style.backgroundColor = '#f0f0f0';
});
dropZone.addEventListener('dragleave', () => {
dropZone.style.backgroundColor = '';
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.style.backgroundColor = '';
handleFiles(e.dataTransfer.files);
});
fileInput.addEventListener('change', (e) => {
handleFiles(e.target.files);
});
function handleFiles(files) {
const formData = new FormData();
formData.append('username', 'JavaScript用户');
formData.append('description', '通过JavaScript上传');
for (let file of files) {
formData.append('file', file);
}
fetch('/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
uploadResult.innerHTML = '<h3>上传结果</h3><pre>' + JSON.stringify(data, null, 2) + '</pre>';
uploadResult.style.display = 'block';
})
.catch(error => {
uploadResult.innerHTML = '<h3>上传错误</h3><p>' + error.message + '</p>';
uploadResult.style.display = 'block';
});
}
</script>
</body>
</html>
`);
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
server.listen(3000, () => {
console.log('文件上传服务器启动:http://localhost:3000');
console.log('上传目录:./uploads');
});文件上传处理要点:
通过本节Node.js处理POST请求教程的学习,你已经掌握:
A: POST请求通过请求体传输数据,支持大量数据和复杂格式;GET请求通过URL参数传输,有长度限制。POST更安全,不会在浏览器历史和服务器日志中暴露敏感数据。
A: 对于大文件,建议使用流式处理,分块上传,设置合理的超时时间。可以实现断点续传功能,使用临时文件存储,上传完成后再移动到最终位置。
A: 1)验证文件类型和扩展名;2)限制文件大小;3)使用唯一文件名;4)将上传文件存储在Web根目录外;5)扫描恶意代码;6)设置适当的文件权限。
A: 建议在多个层次进行验证:1)HTTP层验证格式和大小;2)业务逻辑层验证数据完整性;3)数据库层进行最终约束检查。这样可以提供更好的错误信息和安全性。
A: 1)使用流式处理避免内存占用;2)实现请求体缓存;3)使用连接池;4)异步处理非关键操作;5)实现适当的限流机制;6)优化数据验证逻辑。
"掌握POST请求处理是Web开发的核心技能。从简单的表单提交到复杂的文件上传,每一种数据格式的处理都为你的后端开发能力增添新的维度。继续实践,向全栈开发专家的目标前进!"