Node.js HTTP 服务器基础
核心知识点
HTTP 模块简介
http 模块是 Node.js 的核心模块之一,它提供了创建 HTTP 服务器和客户端的功能。通过 http 模块,我们可以:
- 创建 HTTP 服务器
- 处理 HTTP 请求
- 发送 HTTP 响应
- 创建 HTTP 客户端
创建 HTTP 服务器
使用 http.createServer() 方法创建 HTTP 服务器:
const http = require('http');
const server = http.createServer((req, res) => {
// 处理请求和发送响应
});
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});请求对象 (req)
req 对象代表 HTTP 请求,它包含了请求的信息:
req.url:请求路径req.method:请求方法(GET, POST, PUT, DELETE 等)req.headers:请求头req.httpVersion:HTTP 版本
响应对象 (res)
res 对象代表 HTTP 响应,它用于发送响应给客户端:
res.writeHead(statusCode, headers):设置响应头res.write(data):发送响应体数据res.end(data):结束响应并发送数据res.statusCode:设置响应状态码
服务器监听
使用 server.listen() 方法启动服务器并监听指定的端口:
server.listen(port, hostname, backlog, callback);实用案例
案例一:创建简单的 HTTP 服务器
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
// 设置响应状态码和响应头
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
// 发送响应体并结束响应
res.end('Hello, Node.js HTTP Server!\n');
});
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});案例二:根据请求路径返回不同内容
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
// 设置响应头
res.setHeader('Content-Type', 'text/plain');
// 根据请求路径返回不同内容
switch (req.url) {
case '/':
res.statusCode = 200;
res.end('欢迎访问首页!\n');
break;
case '/about':
res.statusCode = 200;
res.end('关于我们\n');
break;
case '/contact':
res.statusCode = 200;
res.end('联系我们\n');
break;
default:
res.statusCode = 404;
res.end('404 Not Found\n');
break;
}
});
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});案例三:处理不同的 HTTP 请求方法
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
// 设置响应头
res.setHeader('Content-Type', 'text/plain');
// 根据请求方法和路径处理请求
if (req.url === '/api/data') {
switch (req.method) {
case 'GET':
res.statusCode = 200;
res.end('GET 请求:获取数据\n');
break;
case 'POST':
res.statusCode = 200;
res.end('POST 请求:创建数据\n');
break;
case 'PUT':
res.statusCode = 200;
res.end('PUT 请求:更新数据\n');
break;
case 'DELETE':
res.statusCode = 200;
res.end('DELETE 请求:删除数据\n');
break;
default:
res.statusCode = 405;
res.setHeader('Allow', 'GET, POST, PUT, DELETE');
res.end('方法不允许\n');
break;
}
} else {
res.statusCode = 404;
res.end('404 Not Found\n');
}
});
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});案例四:读取并返回 HTML 文件
const http = require('http');
const fs = require('fs');
const path = require('path');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
// 处理根路径请求
if (req.url === '/' || req.url === '/index.html') {
// 读取 HTML 文件
const filePath = path.join(__dirname, 'index.html');
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('服务器内部错误\n');
return;
}
// 返回 HTML 内容
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(data);
});
} else {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('404 Not Found\n');
}
});
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});案例五:解析 URL 查询参数
const http = require('http');
const url = require('url');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
// 解析 URL
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname;
const query = parsedUrl.query;
res.setHeader('Content-Type', 'text/plain');
if (pathname === '/greet') {
// 获取查询参数中的名字
const name = query.name || 'World';
res.statusCode = 200;
res.end(`Hello, ${name}!\n`);
} else if (pathname === '/add') {
// 计算两个数的和
const a = parseInt(query.a) || 0;
const b = parseInt(query.b) || 0;
const sum = a + b;
res.statusCode = 200;
res.end(`Sum of ${a} and ${b} is ${sum}\n`);
} else {
res.statusCode = 404;
res.end('404 Not Found\n');
}
});
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});学习目标
- 理解 HTTP 服务器概念:掌握 HTTP 服务器的基本原理和工作机制
- 使用 http 模块:学会使用 Node.js 的 http 模块创建 HTTP 服务器
- 处理 HTTP 请求:能够处理不同路径和方法的 HTTP 请求
- 发送 HTTP 响应:学会设置响应头和发送响应体
- 读取静态文件:能够读取并返回 HTML 等静态文件
- 解析 URL 参数:学会解析 URL 中的查询参数
代码优化建议
1. 合理组织服务器代码
不好的做法:
const http = require('http');
const server = http.createServer((req, res) => {
// 所有逻辑都在一个回调函数中
if (req.url === '/') {
// 处理根路径
} else if (req.url === '/about') {
// 处理 about 路径
} else if (req.url === '/contact') {
// 处理 contact 路径
} else {
// 处理 404
}
});
server.listen(3000);好的做法:
const http = require('http');
// 处理不同路径的函数
function handleRoot(req, res) {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!\n');
}
function handleAbout(req, res) {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('About Page\n');
}
function handleContact(req, res) {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Contact Page\n');
}
function handleNotFound(req, res) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('404 Not Found\n');
}
// 服务器回调函数
const server = http.createServer((req, res) => {
switch (req.url) {
case '/':
handleRoot(req, res);
break;
case '/about':
handleAbout(req, res);
break;
case '/contact':
handleContact(req, res);
break;
default:
handleNotFound(req, res);
break;
}
});
server.listen(3000, () => {
console.log('服务器运行在 http://127.0.0.1:3000/');
});2. 错误处理
不好的做法:
const http = require('http');
const fs = require('fs');
const server = http.createServer((req, res) => {
fs.readFile('index.html', 'utf8', (err, data) => {
// 没有错误处理
res.end(data);
});
});
server.listen(3000);好的做法:
const http = require('http');
const fs = require('fs');
const server = http.createServer((req, res) => {
fs.readFile('index.html', 'utf8', (err, data) => {
if (err) {
console.error('读取文件错误:', err);
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end('服务器内部错误\n');
return;
}
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(data);
});
});
server.listen(3000, () => {
console.log('服务器运行在 http://127.0.0.1:3000/');
});3. 使用 URL 模块解析路径
不好的做法:
const http = require('http');
const server = http.createServer((req, res) => {
// 手动解析路径和查询参数
const parts = req.url.split('?');
const pathname = parts[0];
const queryString = parts[1] || '';
const query = {};
if (queryString) {
queryString.split('&').forEach(pair => {
const [key, value] = pair.split('=');
query[key] = decodeURIComponent(value);
});
}
// 处理请求
});
server.listen(3000);好的做法:
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
// 使用 url 模块解析
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname;
const query = parsedUrl.query;
// 处理请求
});
server.listen(3000);常见问题与解决方案
问题1:服务器启动失败
原因:
- 端口被占用
- 权限不足(使用低于 1024 的端口)
解决方案:
- 更改端口号
- 使用 sudo 命令(仅在必要时)
问题2:静态文件返回乱码
原因:
- 没有设置正确的字符编码
解决方案:
- 在读取文件时指定编码
- 设置正确的 Content-Type 响应头
问题3:请求路径匹配问题
原因:
- 路径匹配不精确
- 没有考虑查询参数
解决方案:
- 使用 url.parse() 解析路径
- 只匹配 pathname 部分
问题4:服务器崩溃
原因:
- 未捕获的错误
- 异步操作中的错误
解决方案:
- 添加错误处理
- 使用 try/catch 捕获同步错误
- 在回调函数中处理异步错误
总结
通过本教程的学习,你应该能够:
- 理解 HTTP 服务器的基本概念和工作原理
- 使用 Node.js 的 http 模块创建简单的 HTTP 服务器
- 处理不同路径和方法的 HTTP 请求
- 发送带有正确响应头的 HTTP 响应
- 读取并返回静态文件
- 解析 URL 中的查询参数
HTTP 服务器是 Node.js 的核心功能之一,掌握这些基础知识对于学习更高级的 Web 框架(如 Express)非常重要。在后续章节中,我们将学习如何使用 Express 框架来更方便地创建和管理 HTTP 服务器。