Node.js开发实战
Node.js知识点
Node.js内置模块包括了一系列为常见任务提供封装的模块,如文件系统操作、HTTP 服务器与客户端、加密等。这些模块可以通过require函数直接引入到你的Node.js程序中,无需安装额外的包。一些常用的内置模块包括:
- fs
:用于文件系统相关操作,如读写文件。
- http
和https
:用于创建HTTP服务器或客户端。
- path
:提供了一些实用工具函数,用于处理文件与目录的路径。
- crypto
:提供加密功能,包括对称加密、哈希算法等。
- events
:允许创建、触发、监听自定义事件。
非阻塞I/O
非阻塞I/O是指I/O操作(如文件读写、网络请求等)不会导致程序暂停等待操作完成。相反,程序可以继续执行其他任务,并在I/O操作完成时收到通知。这与传统的同步(阻塞)I/O形成对比,后者在操作完成之前会挂起执行线程。
异步编程之Callback
Callback(回调函数)是异步编程的基本概念,指的是被异步操作完成时调用的函数。它是实现非阻塞I/O的一种方式。Node.js广泛使用回调来处理异步操作。例如,读取文件时,你会提供一个函数作为fs.readFile
的参数,该函数会在读取操作完成后被调用。
const fs = require('fs');
fs.readFile('/path/to/file', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
事件循环
Node.js的事件循环是其异步行为的核心。它允许Node.js执行非阻塞I/O操作——尽管JavaScript是单线程的——通过将事件(如文件读取完成)的处理和执行放入事件队列中,并在主程序执行完毕后再按顺序处理这些事件。
异步编程之Promise
Promise是异步编程的一种更先进的模式,比传统的回调函数方法提供了更好的错误处理和链式调用。它表示一个可能现在还不知道结果的操作,但将来会知道结果的对象。
const promise = new Promise((resolve, reject) => {
fs.readFile('/path/to/file', 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
promise.then(data => {
console.log(data);
}).catch(err => {
console.error(err);
});
异步编程之async/await
async/await
是建立在Promise之上的语法糖,使异步代码看起来和同步代码类似,更容易阅读和维护。async
关键字可以用来声明一个函数是异步的,而await
关键字用于等待一个Promise完成并获取其结果。
async function readFile() {
try {
const data = await fs.promises.readFile('/path/to/file', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
}
readFile();
通过这些概念和代码示例,你可以看到Node.js如何通过事件循环和异步编程模型(如Callback、Promise、async/await)有效地处理非阻塞I/O操作,使得能够构建高性能且高效的应用。
HTTP服务器
HTTP服务器是一种软件服务器,用于处理客户端(如Web浏览器)通过HTTP协议发送的请求,并回应相应的内容,这些内容可能是HTML页面、图片、文件或其他类型的数据。HTTP服务器监听特定的端口(如80或443),等待并处理来自客户端的请求。
Node.js通过内置的http
模块提供了创建HTTP服务器的能力,这使得构建基本的HTTP服务器非常简单。
步骤1: 引入HTTP模块
首先,你需要引入Node.js的http
模块。
步骤2: 创建HTTP服务器
使用http.createServer()
方法创建一个HTTP服务器,该方法接收一个回调函数作为参数,该回调函数会处理即将到来的HTTP请求。此回调函数有两个参数:req
(请求对象)和res
(响应对象)。
步骤3: 监听端口
最后,使用服务器对象的listen
方法监听一个端口,等待客户端的连接。
const http = require('http');
// 创建HTTP服务器
const server = http.createServer((req, res) => {
// 设置响应头
res.writeHead(200, {'Content-Type': 'text/plain'});
// 发送响应数据 "Hello World"
res.end('Hello World\n');
});
// 监听3000端口
server.listen(3000, () => {
console.log('Server running at http://127.0.0.1:3000/');
});
在这个例子中,服务器被配置为监听本地的3000端口。对于所有到达的HTTP请求,无论URL是什么,服务器都会响应状态码200(表示成功),并返回纯文本内容"Hello World"。
要运行这个服务器,你需要将这段代码保存到一个.js
文件中,比如server.js
,然后在命令行中使用Node.js运行这个文件:
node server.js
运行后,打开Web浏览器访问http://127.0.0.1:3000/
,你应该会看到显示了“Hello World”。
这是创建HTTP服务器的最基本方法,但Node.js的http
模块提供了丰富的API来处理更复杂的情况,如处理不同的HTTP方法(GET、POST等)、路由、设置cookies、处理文件上传等。
Node.js的http
模块确实提供了一系列功能丰富的API,允许开发者处理更复杂的HTTP服务器场景。这些功能可以帮助你实现更高级的功能,比如路由控制、处理不同的HTTP请求方法、设置HTTP头、管理cookies以及文件上传等。让我们通过一些示例来探讨如何使用这些API。
处理不同的HTTP请求方法
HTTP协议定义了多种请求方法,如GET、POST、PUT等。你可以通过检查req.method
来响应不同类型的请求。
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'GET') {
res.end('Received a GET request');
} else if (req.method === 'POST') {
res.end('Received a POST request');
} else {
res.statusCode = 405; // Method Not Allowed
res.end();
}
});
server.listen(3000);
路由控制
在更复杂的应用中,你可能需要根据请求的URL来提供不同的响应。这可以通过简单的条件语句实现,尽管对于复杂应用,使用专门的路由库(如express
)会更方便。
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/') {
res.end('Home Page');
} else if (req.url === '/about') {
res.end('About Page');
} else {
res.statusCode = 404; // Not Found
res.end('Page Not Found');
}
});
server.listen(3000);
设置HTTP头和管理Cookies
HTTP头部用于提供关于HTTP请求或响应的信息。例如,你可以设置内容类型或处理cookies。
const http = require('http');
const server = http.createServer((req, res) => {
// 设置内容类型
res.setHeader('Content-Type', 'text/html');
// 设置cookie
res.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
res.end('<p>This is an HTML paragraph</p>');
});
server.listen(3000);
处理文件上传
处理文件上传稍微复杂一些,通常需要处理multipart/form-data
类型的POST请求。Node.js核心模块支持这一点,但处理起来相对繁琐。许多人会转而使用如multer
、formidable
等第三方库来简化文件上传。
以下是一个使用Node.js原生方式接收文本数据的简化示例。对于文件,流程类似,但需要更多的代码来处理文件流和文件存储。
const http = require('http');
const { StringDecoder } = require('string_decoder');
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
const decoder = new StringDecoder('utf-8');
let body = '';
req.on('data', (chunk) => {
body += decoder.write(chunk);
});
req.on('end', () => {
body += decoder.end();
console.log(body); // 打印POST请求体
res.end('POST data received');
});
} else {
res.statusCode = 404;
res.end();
}
});
server.listen(3000);
在 Node.js 中,反向代理和缓存服务是两种常用的技术,用于提高网站和应用的性能和可伸缩性。这里将分别解释它们是什么,并提供代码示例来说明如何在 Node.js 项目中实现它们。
反向代理(Reverse Proxy)
反向代理位于客户端和服务器之间,接收客户端的请求然后转发给内部服务器。它可以作为负载均衡器来分发流量、增加安全性(通过隐藏服务器真实IP)、缓存内容以及压缩数据等。Node.js 可以利用 http-proxy
库来创建反向代理服务器。
代码示例:
安装 http-proxy
模块:
npm install http-proxy --save
创建一个简单的反向代理服务器:
const http = require('http');
const httpProxy = require('http-proxy');
// 创建一个代理服务器
const proxy = httpProxy.createProxyServer({});
// 创建你的目标服务器
http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('响应来自目标服务器');
res.end();
}).listen(9000);
// 创建反向代理服务器
http.createServer(function(req, res) {
// 在这里可以执行任何预处理,然后转发请求
proxy.web(req, res, { target: 'http://localhost:9000' });
}).listen(8000);
console.log("反向代理运行在 http://localhost:8000");
缓存服务(Caching)
缓存是存储请求内容的副本,以便于快速访问。在 Node.js 中,缓存可以通过多种方式实现,包括内存存储、文件系统或专用缓存服务器(如 Redis)。缓存可以显著减少数据库的查询次数,提高响应速度。
内存缓存示例:
安装 node-cache
模块:
npm install node-cache --save
使用 node-cache
创建一个简单的缓存例子:
const NodeCache = require("node-cache");
const myCache = new NodeCache();
const key = "uniqueKey";
const value = "存储的数据";
// 存储数据到缓存中,设置存活时间为10分钟(600秒)
myCache.set(key, value, 600);
// 从缓存中获取数据
const cachedData = myCache.get(key);
if (cachedData) {
console.log("从缓存中获取到的数据:", cachedData);
} else {
console.log("缓存中没有找到数据");
}
结合反向代理和缓存
在实际应用中,反向代理和缓存经常一起使用。反向代理可以负责接收客户端请求、查询缓存;如果缓存中有响应数据,则直接返回给客户端,如果没有,则查询后端服务,同时将响应结果缓存起来,以便于下次快速响应。
转载自:https://juejin.cn/post/7344774767990620211