文章目录
- [Node http模块](#Node http模块)
Node http模块
概述
HTTP 模块是 Node.js 的核心模块,用于创建 HTTP 服务器和客户端,处理网络请求和响应。提供了底层、高性能的 HTTP 通信能力。
核心API
请求对象
属性:
- url:请求的URL
- method:请求方法(GET、POST等)
- headers:请求头
- httpVersion:http版本
- socket:自称网络套接字
方法:
- setTimeout():设置请求超时时间
- destroy():销毁请求连接
监听方法:
- req.on("data",callback):监听数据接收
- req.on("end",callback):监听数据接收完成
- req.on("error",callback):监听错误事件
- req.on("close",callback):监听连接关闭
响应对象
属性:
- statusCode:响应状态码
- statusMessage:响应状态消息
方法:
- writeHead():发送响应头和状态码
- setHeader():设置单个响应头
- getHeader(name):获取指定响应头值
- removeHeader(name):移除指定响应头
- getHeaders():获取所有响应头
- write():向响应流写入数据
- end():结束响应,必须调用
重定向:
- location(path):设置重定向路径
- redirect(status,path):发送重定向响应
用法
创建服务器
javascript
import http from "http";
const server = http.createServer((request, response) => {
response.writeHead(200, {"Content-Type": "text/plain"});
response.end("Hello, World!");
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000");
});
可以通过 http://localhost:3000 访问服务器。
请求对象
javascript
const server = http.createServer((req, res) => {
// 基本信息
console.log('请求方法:', req.method); // GET, POST, PUT, DELETE
console.log('请求URL:', req.url); // /path?query=string
console.log('HTTP版本:', req.httpVersion); // 1.1
// 请求头
console.log('请求头:', req.headers);
console.log('用户代理:', req.headers['user-agent']);
console.log('接受类型:', req.headers['accept']);
// URL解析
const url = require('url');
const parsedUrl = url.parse(req.url, true);
console.log('路径:', parsedUrl.pathname); // /api/users
console.log('查询参数:', parsedUrl.query); // { id: '1' }
console.log('哈希:', parsedUrl.hash); // #section
res.end('请求信息已记录');
});
响应对象
javascript
const server = http.createServer((req, res) => {
// 1. 设置状态码
res.statusCode = 200; // 或 404, 500 等
// 2. 设置响应头
res.setHeader('Content-Type', 'text/html');
res.setHeader('X-Powered-By', 'Node.js');
// 3. 或者一次性设置
res.writeHead(200, {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
'Set-Cookie': ['token=abc123; HttpOnly']
});
// 4. 写入响应体
res.write('<h1>标题</h1>');
res.write('<p>段落内容</p>');
// 5. 结束响应
res.end('响应结束');
});
处理不同HTTP方法
javascript
import http from "http";
import url from "url";
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
if (method === "GET" && path === "/api/users") {
// 获取用户列表
res.writeHead(200, {"Content-Type": "application/json"});
const users = [
{name: "小白", age: 18},
{name: "小黑", age: 28},
];
res.end(JSON.stringify(users));
} else if (method === "POST" && path === "/api/new_user") {
// 创建新用户
res.writeHead(200, {"Content-Type": "application/json"});
const newUser = {name: "小新", age: 8};
res.end(JSON.stringify(newUser));
} else {
res.writeHead(404, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "接口不存在"}));
}
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000");
});
处理get请求参数
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form action="/params" method="GET">
<label>姓名: <input type="text" name="name" placeholder="输入姓名"/></label><br>
<label>年龄: <input type="number" name="age" placeholder="输入年龄"/></label><br>
<label>城市: <input type="text" name="city" placeholder="输入城市"/></label><br>
<button type="submit">提交</button>
</form>
</body>
</html>
javascript
import fs from "fs";
import http from "http";
import url from "url";
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
const query = parsedUrl.query;
if (method === "GET" && path === "/params") {
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify(query));
} else if (method === "GET" && path === "/") {
fs.readFile(`index.html`, (err, data) => {
res.writeHead(200, {"Content-Type": "text/html"});
res.end(data.toString());
});
} else {
res.writeHead(404, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "接口不存在"}));
}
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000");
});
处理post请求参数
处理表单提交:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form action="/params" method="POST">
<label>姓名: <input type="text" name="name" placeholder="输入姓名"/></label><br>
<label>年龄: <input type="number" name="age" placeholder="输入年龄"/></label><br>
<label>城市: <input type="text" name="city" placeholder="输入城市"/></label><br>
<button type="submit">提交</button>
</form>
</body>
</html>
javascript
import fs from "fs";
import http from "http";
import querystring from "querystring";
import url from "url";
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
const contentType = req.headers["content-type"];
if (method === "POST" && path === "/params" && contentType === "application/x-www-form-urlencoded") {
let body = "";
req.on("data", chunk => {
body += chunk.toString();
});
req.on("end", () => {
const formData = querystring.parse(body);
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
});
res.end(JSON.stringify(formData));
});
} else if (method === "GET" && path === "/") {
const data = fs.readFileSync("index.html");
res.writeHead(200, {"Content-Type": "text/html"});
res.end(data.toString());
} else {
res.writeHead(404, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "接口不存在"}));
}
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000");
});
处理JSON数据提交:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form id="form" action="/params" method="POST">
<label>姓名: <input type="text" name="name" placeholder="输入姓名"/></label><br>
<label>年龄: <input type="number" name="age" placeholder="输入年龄"/></label><br>
<label>城市: <input type="text" name="city" placeholder="输入城市"/></label><br>
<button type="submit">提交</button>
</form>
<script>
const form = document.getElementById("form");
form.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(form);
const formObject = Object.fromEntries(formData.entries());
try {
const response = await fetch("/params", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(formObject)
});
const result = await response.json();
console.log("提交结果:", result);
} catch (error) {
console.error("提交失败:", error);
}
});
</script>
</body>
</html>
javascript
import fs from "fs";
import http from "http";
import url from "url";
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
const contentType = req.headers["content-type"];
if (method === "POST" && path === "/params" && contentType === "application/json") {
let body = "";
req.on("data", chunk => {
body += chunk.toString();
});
req.on("end", () => {
let postData;
if (body.trim()) {
postData = JSON.parse(body);
} else {
postData = {};
}
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
});
res.end(JSON.stringify(postData));
});
} else if (method === "GET" && path === "/") {
const data = fs.readFileSync("index.html");
res.writeHead(200, {"Content-Type": "text/html"});
res.end(data.toString());
} else {
res.writeHead(404, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "接口不存在"}));
}
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000");
});
响应图片
javascript
import fs from "fs";
import http from "http";
const server = http.createServer((req, res) => {
const buffer = fs.readFileSync("abc.png");
res.writeHead(200, {"Content-Type": "image/jpeg"});
res.end(buffer);
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000");
});
响应视频
javascript
import fs from "fs";
import http from "http";
const server = http.createServer((req, res) => {
const buffer = fs.readFileSync("a.mp4");
res.writeHead(200, {"Content-Type": "video/mp4"});
res.end(buffer);
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000");
});
处理css文件
javascript
import fs from "fs";
import http from "http";
import url from "url";
const server = http.createServer((req, res) => {
const {method} = req;
const parsedUrl = url.parse(req.url, true);
console.log(req.url);
const path = parsedUrl.pathname;
if (method === "GET" && path === "/") {
const buffer = fs.readFileSync("index.html");
res.writeHead(200, {"Content-Type": "text/html"});
res.end(buffer);
} else if (method === "GET" && path === "/index.css") {
const buffer = fs.readFileSync("index.css");
res.writeHead(200, {"Content-Type": "text/css"});
res.end(buffer);
}
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000");
});
重定向
javascript
const http = require("http");
const fs = require("fs");
const server = http.createServer((req, res) => {
res.writeHead(302, {"Location": "https://www.baidu.com/"});
res.end();
});
server.listen(9000, () => {
console.log(`Server listening on ${server.address().port}`);
});
文件上传
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<h1>文件上传</h1>
<h2>单文件上传</h2>
<form action="/upload" method="POST" enctype="multipart/form-data">
<label>选择文件</label>
<input type="file" name="file" required><br>
<label>文件描述(可选)</label>
<input type="text" name="description" placeholder="请输入文件描述"><br>
<button type="submit">上传文件</button>
</form>
<h2>多文件上传</h2>
<form action="/upload" method="POST" enctype="multipart/form-data">
<label>选择文件</label>
<input type="file" name="files" multiple required><br>
<button type="submit">上传文件</button>
</form>
</body>
</html>
javascript
import fs from "fs";
import http from "http";
import path, {dirname} from "path";
import {fileURLToPath} from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const uploadDir = path.join(__dirname, "upload");
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, {recursive: true});
}
function parseMultipart(req, boundary) {
return new Promise((resolve, reject) => {
let body = "";
req.on("data", (chunk) => {
body += chunk.toString();
});
req.on("end", () => {
try {
const parts = body.split(`--${boundary}`);
const fields = {};
const files = [];
for (let i = 1; i < parts.length - 1; i++) {
const part = parts[i].trim();
if (!part) continue;
const [headers, ...contentArray] = part.split("\r\n\r\n");
const content = contentArray.join("\r\n\r\n");
const dispositionMatch = headers.match(/Content-Disposition:\s*form-data;\s*name="([^"]+)"(?:;\s*filename="([^"]+)")?/i);
if (!dispositionMatch) continue;
const fieldName = dispositionMatch[1];
const filename = dispositionMatch[2];
if (filename) {
// 这是一个文件字段
const contentTypeMatch = headers.match(/Content-Type:\s*([^\r\n]+)/i);
const contentType = contentTypeMatch ? contentTypeMatch[1] : "application/octet-stream";
const file = {
fieldName,
originalFilename: filename,
contentType,
size: Buffer.byteLength(content, "utf8") - 2, // 减去 \r\n
buffer: Buffer.from(content.substring(0, content.length - 2), "utf8") // 去掉最后的 \r\n
};
files.push(file);
// 保存文件到上传目录
const filePath = path.join(uploadDir, filename);
fs.writeFileSync(filePath, file.buffer);
file.savedPath = filePath;
} else {
// 这是一个普通字段
fields[fieldName] = content.trim().substring(0, content.length - 2); // 去掉最后的 \r\n
}
}
resolve({fields, files});
} catch (error) {
reject(error);
}
});
req.on("error", (error) => {
reject(error);
});
});
}
const server = http.createServer(async (req, res) => {
const method = req.method;
const url = req.url;
if (method === "GET" && url === "/") {
const data = fs.readFileSync("upload.html");
res.writeHead(200, {"Content-Type": "text/html"});
res.end(data.toString());
} else if (method === "POST" && url === "/upload") {
const contentType = req.headers["content-type"];
if (!contentType || !contentType.includes("multipart/form-data")) {
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "请求必须是 multipart/form-data 类型"}));
return;
}
const boundaryMatch = contentType.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
if (!boundaryMatch) {
res.writeHead(400, {"Content-Type": "application/json"});
res.end(JSON.stringify({
error: "无法找到边界字符串"
}));
return;
}
const boundary = boundaryMatch[1] || boundaryMatch[2];
// 解析 multipart 数据
const {fields, files} = await parseMultipart(req, boundary);
console.log("接收到的字段:", fields);
console.log("接收到的文件:", files);
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify({success: "文件上传成功"}));
} else {
res.writeHead(404, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "接口不存在"}));
}
});
server.listen(9000, () => {
console.log("服务器运行在 http://localhost:9000");
});
文件下载
javascript
import fs from "fs";
import http from "http";
import path, {dirname} from "path";
import {fileURLToPath} from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const uploadDir = path.join(__dirname, "upload");
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, {recursive: true});
}
const server = http.createServer(async (req, res) => {
const method = req.method;
const url = req.url;
console.log(method);
console.log(url);
if (method === "GET" && url.startsWith("/download/")) {
// 获取文件名
const fileName = decodeURIComponent(url.substring(10));
const filePath = path.join(uploadDir, fileName);
if (!fs.existsSync(filePath)) {
res.writeHead(404, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "文件不存在"}));
return;
}
try {
console.log("fileName: ", fileName);
const fileContent = fs.readFileSync(filePath);
const stats = fs.statSync(filePath);
res.writeHead(200, {
"Content-Type": "application/octet-stream",
"Content-Length": stats.size,
"Content-Disposition": `attachment; filename="${fileName}"`
});
res.end(fileContent);
} catch (error) {
res.writeHead(500, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "无法读取文件"}));
}
} else {
res.writeHead(404, {"Content-Type": "application/json"});
res.end(JSON.stringify({error: "接口不存在"}));
}
});
server.listen(9000, () => {
console.log("服务器运行在 http://localhost:9000");
});