深入掌握Node.js HTTP模块:从开始到放弃
文章目录
- 一、HTTP模块入门:从零搭建第一个服务器
- 1.1 基础概念解析
- 1.2 手把手创建服务器
- 二、核心功能深入解析
- 2.1 处理不同请求类型
- 2.2 实现文件下载功能
- 三、常见问题解决方案
- 3.1 跨域问题处理
- 3.2 防止服务崩溃
- 3.3 调试技巧
- 四、安全最佳实践
- 4.1 请求头安全设置
- 4.2 速率限制(防止DDoS攻击)
- 五、简易版博客系统
- 5.1 项目结构
- 5.2 环境准备
- 5.3 核心代码实现
一、HTTP模块入门:从零搭建第一个服务器
1.1 基础概念解析
HTTP 模块是什么?
Node.js内置的 http 模块提供了创建 HTTP 服务器和客户端的能力。就像快递公司:
- 服务器:像仓库,存储货物(数据)
- 客户端:像快递员,负责收发货物(请求和响应)
核心对象解释:
http.createServer
:创建服务器req
对象:包含客户端请求的信息(地址、请求头等)res
对象:用来给客户端发送响应
1.2 手把手创建服务器
// 导入模块(类似取快递工具)
const http = require('http');// 创建服务器(建立仓库)
const server = http.createServer((req, res) => {// 设置响应头(告诉快递员包裹类型)res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); // 明确指定编码,不然运行之后是乱码// 发送响应内容(实际运送的货物)res.end('<h1>欢迎来到我的网站!</h1>');
})// 启动监听(设置仓库门牌号)
server.listen(3000, () => {console.log('服务器已在 http://localhost:3000 启动')
})
二、核心功能深入解析
2.1 处理不同请求类型
GET 请求参数获取
const { URL } = require('url');server.on('request', (req, res) => {// 解析URL(类似拆包裹看地址标签)const urlObj = new URL(req.url, `http://${req.headers.host}`);// 获取查询参数(比如?name=John)console.log(urlObj.searchParams.get('name')); // 输出 John
})
POST 请求数据处理
let body = [];
req.on('data', chunk => {body.push(chunk); //接收数据块(像接收多个包裹)
}).on('end', () => {body = Buffer.concat(body).toString(); // 合并所有数据块console.log('收到POST数据:', body);
})
2.2 实现文件下载功能
const fs = require('fs');function downloadFile(res, filePath) {// 设置响应头(高速浏览器这是要下载的文件)res.writeHead(200, {'Content-Type': 'application/octet-stream','Content-Disposition': `attachment; filename=${path.basename(filePath)}`});// 创建文件流(像打开水龙头放水)const fileStream = fs.createReadStream(filePath);fileStream.pipe(res); // 将文件流导向响应
}
三、常见问题解决方案
3.1 跨域问题处理
// 在响应头中添加CORS支持
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
3.2 防止服务崩溃
// 全局错误捕获
process.on('uncaughtException', (err) => {console.error('全局异常捕获:', err);// 可以记录日志或发送警报
});// 处理Promise拒绝
process.on('unhandledRejection', (reason, promise) => {console.error('未处理的Promise拒绝:', reason);
});
3.3 调试技巧
使用 curl 测试接口:
# 测试GET请求
curl http://localhost:3000/api/data# 测试POST请求
curl -X POST -d "username=john" http://localhost:3000/login
四、安全最佳实践
4.1 请求头安全设置
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Content-Security-Policy', "default-src 'self'");
4.2 速率限制(防止DDoS攻击)
const rateLimit = require('express-rate-limit');const limiter = rateLimit({windowMs: 15 * 60 * 1000, // 15分钟max: 100 // 每个IP最多100次请求
});// 应用中间件
server.use(limiter);
五、简易版博客系统
5.1 项目结构
/my-blog
├── data/ # 数据存储
│ └── articles.json
├── public/ # 静态资源
│ ├── css/
│ └── js/
│ └── index.html
├── controllers/ # 业务逻辑
│ └── articleController.js
├── routes/ # 路由配置
│ └── articleRoutes.js
├── utils/ # 工具函数
│ └── fileUtils.js
└── server.js # 入口文件
5.2 环境准备
1.初始化项目
mkdir my-blog && cd my-blog
npm init -y
2.安装依赖
npm install uuid # 生成唯一ID
5.3 核心代码实现
1.数据存储(data/articles.json)
{"articles": [{"id": "1","title": "Node.js入门指南","content": "Node.js是一个基于Chrome V8引擎的JavaScript运行环境...","createdAt": "2023-08-20"}]
}
2.工具函数(utils/fileUtils.js)
const fs = require('fs').promises;
const path = require('path');const dataPath = path.join(__dirname, '../data/articles.json');async function readData() {try {const data = await fs.readFile(dataPath, 'utf8');return JSON.parse(data);} catch (err) {return { articles: [] };}
}async function writeData(data) {await fs.writeFile(dataPath, JSON.stringify(data, null, 2));
}module.exports = { readData, writeData };
3. 控制器(controllers/articleController.js)
const { v4: uuidv4 } = require('uuid');
const { readData, writeData } = require('../utils/fileUtils');// 获取所有文章
async function getAllArticles() {const data = await readData();return data.articles;
}// 创建新文章
async function createArticle(title, content) {const data = await readData();const newArticle = {id: uuidv4(),title,content,createdAt: new Date().toISOString().split('T')[0]};data.articles.push(newArticle);await writeData(data);return newArticle;
}// 删除文章
async function deleteArticle(id) {const data = await readData();data.articles = data.articles.filter(article => article.id !== id);await writeData(data);
}module.exports = { getAllArticles, createArticle, deleteArticle };
4. 路由配置(routes/articleRoutes.js)
const http = require('http');
const fs = require('fs');
const path = require('path');// 假设这是文章数据存储
let articles = [];
let nextId = 1;function handleRoutes(req, res) {const urlParts = req.url.split('/');if (req.url === '/api/articles' && req.method === 'GET') {res.writeHead(200, { 'Content-Type': 'application/json' });res.end(JSON.stringify(articles));} else if (req.url === '/api/articles' && req.method === 'POST') {let body = '';req.on('data', chunk => {body += chunk.toString();});req.on('end', () => {const newArticle = JSON.parse(body);newArticle.id = nextId++;articles.push(newArticle);res.writeHead(201, { 'Content-Type': 'application/json' });res.end(JSON.stringify(newArticle));});} else if (urlParts[1] === 'api' && urlParts[2] === 'articles' && req.method === 'DELETE') {if (urlParts.length === 3) {// 批量删除articles = [];res.writeHead(200, { 'Content-Type': 'application/json' });res.end(JSON.stringify({ message: '所有文章删除成功' }));} else {// 单篇删除const id = parseInt(urlParts[3]);const index = articles.findIndex(article => article.id === id);if (index !== -1) {articles.splice(index, 1);res.writeHead(200, { 'Content-Type': 'application/json' });res.end(JSON.stringify({ message: '文章删除成功' }));} else {res.writeHead(404, { 'Content-Type': 'application/json' });res.end(JSON.stringify({ message: '文章未找到' }));}}} else {res.writeHead(404, { 'Content-Type': 'text/plain' });res.end('Not Found');}
}module.exports = handleRoutes;
5. 主服务器(server.js)
const http = require('http');
const fs = require('fs');
const path = require('path');
const handleRoutes = require('./routes/articleRoutes');// 创建HTTP服务器
const server = http.createServer(async (req, res) => {// 静态文件服务if (req.url.startsWith('/public/')) {const filePath = path.join(__dirname, req.url);fs.readFile(filePath, (err, data) => {if (err) {res.writeHead(404);return res.end('File not found');}res.writeHead(200);res.end(data);});return;}// API路由处理handleRoutes(req, res);
});// 启动服务器
const PORT = 3000;
server.listen(PORT, () => {console.log(`Server running at http://localhost:${PORT}`);
});
6.页面样式跟逻辑
// public/js/app.js
// 加载文章列表的函数
async function loadArticles() {try {const response = await fetch('/api/articles');if (!response.ok) {throw new Error('网络响应失败');}const articles = await response.json();const articlesDiv = document.getElementById('articles');articlesDiv.innerHTML = '';articles.forEach(article => {const articleElement = document.createElement('div');articleElement.innerHTML = `<h2>${article.title}</h2><p>${article.content}</p><button onclick="deleteArticle('${article.id}')">删除文章</button>`;articlesDiv.appendChild(articleElement);});} catch (error) {console.error('加载文章列表时出错:', error);}
}// 删除文章的函数
async function deleteArticle(id) {try {const response = await fetch(`/api/articles/${id}`, {method: 'DELETE'});if (!response.ok) {throw new Error('删除文章失败');}// 重新加载文章列表loadArticles();} catch (error) {console.error('删除文章时出错:', error);}
}// 添加文章的函数
async function addArticle(event) {event.preventDefault();const title = document.getElementById('title').value;const content = document.getElementById('content').value;try {const response = await fetch('/api/articles', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({ title, content })});if (!response.ok) {throw new Error('添加文章失败');}// 清空表单document.getElementById('articleForm').reset();// 重新加载文章列表loadArticles();} catch (error) {console.error('添加文章时出错:', error);}
}// 页面加载完成后自动加载文章列表
window.addEventListener('DOMContentLoaded', loadArticles);
// public/index.html
<!DOCTYPE html>
<html>
<head><!-- 添加字符编码声明 --><meta charset="UTF-8"><title>我的博客</title><link rel="stylesheet" href="/public/css/style.css">
</head>
<body><div id="app"><h1>文章列表</h1><!-- 修改文章表单,移除文件输入框 --><form id="articleForm" onsubmit="addArticle(event)"><input type="text" id="title" placeholder="文章标题" required><textarea id="content" placeholder="文章内容" required></textarea><button type="submit">添加文章</button></form><div id="articles"></div><button onclick="loadArticles()">刷新列表</button></div><script src="/public/js/app.js"></script>
</body>
</html>
// public/css/style.css
body {font-family: Arial, sans-serif;line-height: 1.6;margin: 0;padding: 0;background-color: #f4f4f4;
}#app {width: 80%;margin: auto;overflow: hidden;padding: 20px;
}h1 {color: #333;text-align: center;
}#articleForm {background-color: #fff;padding: 20px;margin-bottom: 20px;border-radius: 5px;box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}#articleForm input[type="text"],
#articleForm textarea {width: 100%;padding: 10px;margin-bottom: 10px;border: 1px solid #ddd;border-radius: 3px;
}#articleForm button {background-color: #333;color: #fff;padding: 10px 20px;border: none;border-radius: 3px;cursor: pointer;
}#articleForm button:hover {background-color: #555;
}#articles div {background-color: #fff;padding: 20px;margin-bottom: 10px;border-radius: 5px;box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}#articles h2 {margin-top: 0;
}
相关文章:
深入掌握Node.js HTTP模块:从开始到放弃
文章目录 一、HTTP模块入门:从零搭建第一个服务器1.1 基础概念解析1.2 手把手创建服务器 二、核心功能深入解析2.1 处理不同请求类型2.2 实现文件下载功能 三、常见问题解决方案3.1 跨域问题处理3.2 防止服务崩溃3.3 调试技巧 四、安全最佳实践4.1 请求头安全设置4.…...

【数据库】并发控制
并发控制 在数据库系统,经常需要多个用户同时使用。同一时间并发的事务可达数百个,这就是并发引入的必要性。 常见的并发系统有三种: 串行事务执行(X),每个时刻只有一个事务运行,不能充分利用…...

Ansys Zemax | 手机镜头设计 - 第 2 部分:光机械封装
本文该系列文章将讨论智能手机镜头模组设计的挑战,涵盖了从概念、设计到制造和结构变形的分析。本文是四部分系列的第二部分,介绍了在 Ansys Speos 环境中编辑光学元件以及在整合机械组件后分析系统。案例研究对象是一家全球运营制造商的智能手机镜头系统…...
湖北理元理律师事务所债务优化实践:在还款与生活间寻找平衡支点
在个人债务规模持续扩大的社会背景下,如何科学管理债务正成为民生焦点。湖北理元理律师事务所通过其服务案例表明:债务优化的本质不是逃避责任,而是建立可持续的还款体系,让债务人保有基本生活尊严。 一、打破“越还越穷”的恶性…...

mcp-go v0.30.0重磅发布!Server端流式HTTP传输、OAuth支持及多项功能革新全面解读!
随着云原生应用和现代分布式系统需求的不断增长,高效、灵活且稳定的通信协议和客户端交互框架成为开发者关注的焦点。作为开源领域备受期待的项目之一,mcp-go再次迎来重要版本更新——v0.30.0正式发布!本次更新版本不仅实现了众多关键功能&am…...
解锁 MCP 中的 JSON-RPC:跨平台通信的奥秘
你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等希望看什么,评论或者私信告诉我! 文章目录 零、 背景一、RPC vs HTTP1.1 什么是RPC1.2 为什么需要 RPC?1.3 RPC 解决了什么…...
流复制(Streaming Replication)与自动故障转移(Failover)实战:用Patroni或Repmgr搭建生产级数据库集群
更多服务器知识,尽在hostol.com 嘿,各位PostgreSQL的“掌舵人”和数据“守护神”们!咱们都知道,PostgreSQL(简称PG)以其强大的功能、稳定性和开源的特性,赢得了越来越多开发者和企业的青睐。但…...

OpenGL Chan视频学习-10 Dealing with Errors in OpenGL
bilibili视频链接: 【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p5&vd_source44b77bde056381262ee55e448b9b1973 函数网站: docs.gl 说明: 1.之后就不再单独整理网站具体函数了,网站直接翻译会…...

美团启动618大促,线上消费节被即时零售传导到线下了?
首先,从市场推广与消费者吸引的角度来看,美团通过联合众多品牌开展大规模促销活动,并发放高额优惠券包,旨在吸引更多消费者参与购物。这种策略有助于提高平台的活跃度和交易量,同时也能够增强用户粘性。对于消费者而言…...

搭建 Select 三级联动架构-东方仙盟插件开发 JavaScript ——仙盟创梦IDE
三级级联开卡必要性 在 “东方仙盟” 相关插件开发中,使用原生 HTML 和 JavaScript 实现三级联动选择(如村庄 - 建筑 - 单元的选择)有以下好处和意义,学校管理: 对游戏体验的提升 增强交互性:玩家能够通…...

服务器如何配置防火墙管理端口访问?
配置服务器防火墙来管理端口访问,是保障云服务器安全的核心步骤。下面我将根据你使用的不同操作系统(Linux: Ubuntu/Debian/CentOS;Windows Server)介绍常用防火墙配置方法。 ✅ 一、Linux 防火墙配置(UFW / firewalld…...
Webhook入门
主要参考资料: 深入解析 Webhook:从原理到实践的全面指南: https://blog.csdn.net/weixin_43114209/article/details/144250750 目录 简介Webhook 与传统 API 调用的区别与轮询 (Polling) 的对比典型工作流程 简介 简单来说,Webhook 是一种“…...
LangChain整合Milvus向量数据库实战:数据新增与删除操作
导读:在AI应用开发中,向量数据库已成为处理大规模语义搜索和相似性匹配的核心组件。本文通过详实的代码示例,深入探讨LangChain框架与Milvus向量数据库的集成实践,为开发者提供生产级别的向量数据管理解决方案。 文章聚焦于向量数…...
LSTM+Transformer混合模型架构文档
LSTMTransformer混合模型架构文档 模型概述 本项目实现了一个LSTMTransformer混合模型,用于超临界机组协调控制系统的数据驱动建模。该模型结合了LSTM的时序建模能力和Transformer的自注意力机制,能够有效捕捉时间序列数据中的长期依赖关系和变量间的复…...
Symbol、Set 与 Map:新数据结构探秘
Symbol、Set 与 Map:新数据结构探秘 引言 ECMAScript 6 (ES6) 引入了三种强大的数据结构:Symbol、Set 与 Map,它们解决了 JavaScript 开发中的特定痛点,为我们提供了更多工具来处理复杂的数据操作。 Symbol:唯一标识…...

Spring Boot+Activiti7入坑指南初阶版
介绍 Activiti 是一个轻量级工作流程和业务流程管理 (BPM) 平台,面向业务人员、开发人员和系统管理员。其核心是一个超快且坚如磐石的 Java BPMN 2 流程引擎。它是开源的,并根据 Apache 许可证分发。Activiti 可以在任何 Java 应用程序、服务器、集群或云中运行。它与 Spri…...

如何在 Odoo 18 中创建 PDF 报告
如何在 Odoo 18 中创建 PDF 报告 Qweb 是 Odoo 强大的模板引擎,旨在轻松将 XML 数据转换为 HTML 文档。其功能特性包括基于属性的自定义、条件逻辑、动态内容插入及多样化的报告模板选项。这种多功能性使 Qweb 成为制作个性化、视觉吸引力强的报告、电子邮件和文档…...

【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用
【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用 文章目录 前言正文配置环境下载源码配置环境变量测试运行修改点说明实际运行情况 参考 前言 本文用来记录 xCoreSDK-Python的调用使用1。 正文 配置环境 配置开发环境,这里使用conda做python环境管理&…...
c/c++的opencv椒盐噪声
在 C/C 中实现椒盐噪声 椒盐噪声(Salt-and-Pepper Noise),也称为脉冲噪声(Impulse Noise),是数字图像中常见的一种噪声类型。它的特点是在图像中随机出现纯白色(盐)或纯黑色&#x…...
C++ TCP程序增加TLS加密认证
TCP为什么要增加TLS TCP程序添加TLS主要是为了解决TCP协议本身的安全缺陷。TCP作为传输层协议,虽然提供了可靠的数据传输,但它是明文传输,存在几个关键的安全问题: 数据泄露风险:TCP传输的数据完全暴露在网络中,任何能够监听网络流量的人都可以直接读取传输内容。这对于…...
构建一个“论文检索 + 推理”知识库服务,支持用户上传 PDF/LATEX 源码后,秒级检索并获得基于内容的问答、摘要、引用等功能
文章目录 1 总体目标 / Overall Goal2 数据管线 / Data Pipeline3 检索策略 / Retrieval Strategy4 服务切分 / Service Decomposition5 Agent & Prompt 设计 / Agent & Prompt6 核心功能 / Core Features7 评测与监控 / Evaluation & Monitoring8 面试亮点 / Inte…...

VLC-QT 网页播放RTSP
先看效果图,代码在文章末尾,包含源码,vlc-qt完整的库 环境说明:VS 2017 QTQt5.13.0 MSVC2017 32位 将vlc_install 目录下的bin,include,lib里所有的东西分别放在qt目录下 bin -> C:\Qt\Qt5.13.0\5.13.0\msvc2017\bin include->C:\Qt\Qt5.13.0\5.13.0\msvc201…...
for(auto a:b)和for(auto a:b)的区别
#include<iostream> using namespace std; int main() {string s( "hello world" );for (auto c:s)c t ;cout<<s<<endl; //结果为hello worldfor (auto &c:s)c t ;cout<<s<<endl; //结果为ttttttttttt }for(auto a:b)中b为一…...
第2章-12 输出三角形面积和周长(走弯路解法)
本题要求编写程序,根据输入的三角形的三条边a、b、c,计算并输出面积和周长。注意:在一个三角形中, 任意两边之和大于第三边。三角形面积计算公式:areas(s−a)(s−b)(s−c),其中s(abc)/2。 import math de…...
Caddy如何在测试环境中使用IP地址配置HTTPS服务
前言 在开发和测试环境中,我们经常需要搭建HTTPS服务进行测试。但通常Let’s Encrypt等证书颁发机构要求使用有效域名,不直接支持IP地址。本文将详细介绍如何使用Caddy在测试环境中通过IP地址配置HTTPS服务,使用自签名证书解决这一问题。 环…...
shell中与>和<相关的数据流重定向操作符整理
shell中与>和<相关的数据流重定向操作符整理 输出重定向操作符>>>2>2>>&> 或 >&&>> 输入重定向操作符<<<<<< 组合重定向2>&1 文件描述符相关重定向[n]< file 和 [n]> file>&- 和 <&…...

【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix
【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix 文章目录 【航天远景 MapMatrix 精品教程】08 Pix4d空三成果导入MapMatrix一、资料准备1.去畸变影像2.相机文件3.外方位元素二、创建工程1.新建工程2.导入照片3.编辑相机文件4.编辑外方位元素文件,导入外方位元…...

创建型设计模式之Prototype(原型)
创建型设计模式之Prototype(原型) 摘要: Prototype(原型)设计模式通过复制现有对象来创建新对象,避免重复初始化操作。该模式包含Prototype接口声明克隆方法、ConcretePrototype实现具体克隆逻辑ÿ…...

JNI开发流程
一. 引言 最近在做一个自己的项目,就是基于FastDDS封装一套JAVA库,让android和java应用可以使用dds的功能。 由于FastDDS是使用C编写的开源库,因此java的类库想要调用FastDDS的接口,需要额外编写一个JNI层的动态库对FastDDS的接口…...

STM32G4 电机外设篇(二) VOFA + ADC + OPAMP
目录 一、STM32G4 电机外设篇(二) VOFA ADC OPAMP1 VOFA1.1 VOFA上位机显示波形 2 ADC2.1 用ADC规则组对板载电压和电位器进行采样 3 OPAMP(运放)3.1 结合STM32内部运放和ADC来完成对三相电流的采样3.2 运放电路分析 附学习参考…...