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");
});
相关推荐
马达加斯加D14 小时前
Web系统设计 --- HTTP + GraphQL
前端·http·graphql
源远流长jerry1 天前
http协议和https协议的连接流程
网络·http·https
松涛和鸣1 天前
44、HTML与HTTP服务器交互笔记
linux·运维·服务器·http·链表·html
源远流长jerry1 天前
DNS解析过程以及CDN流程
http·缓存
REDcker1 天前
WebRTC-HTTP 出口协议 (WHEP) draft-murillo-whep-01 中文翻译
网络协议·http·webrtc
源远流长jerry2 天前
HTTP 1.x ~ HTTP 3 完整详解
网络·网络协议·http
松涛和鸣2 天前
DAY 44 HTML and HTTP Server Interaction Notes
linux·前端·网络·数据库·http·sqlite·html
ps酷教程2 天前
HttpData
http·netty
忆_恒心2 天前
eNSP网络实验:一站式掌握DNS、HTTP、FTP服务器配置全攻略
服务器·网络·网络协议·计算机网络·http·智能路由器