返回给客户端的信息主要分为两部分,分别为响应头和返回给浏览器的内容,在不设置响应头的情况下,默认会设置响应头 Content-Length 和 Date ,代表当前返回给客户端的内容长度和日期。
返回给浏览器的内容可以通过 res 的 write 方法和 end 方法进行发送,write 方法不会断开连接(通常在响应后需要断开与客户端的连接),end 方法会断开连接,在 end 方法存在参数时,会在内部调用 write 将参数内容返回给客户端,并断开连接。
HTTP 客户端
在 net 模块中可以通过 net.createConnection 来创建客户端,并发送请求到服务端,在 http 模块同样可以创建客户端,并向 http 服务器发送请求。
// 客户端:client.js const http = require("http"); // 发送请求的配置 let config = { host: "localhost", port: 3000, method: "get", headers: { a: 1 } }; // 创建客户端 let client = http.request(config, function(res) { // 接收服务端返回的数据 let arr = []; res.on("data", function(data) { arr.push(data); }); res.on("end", function() { console.log(Buffer.concat(arr).toString()); }); }); // 发送请求 client.end();
在 http 模块中通过 request 方法创建客户端,该方法第一个参数为发送请求的配置,包含请求地址、端口号、请求方法以及请求头等,第二个参数为回调函数,在请求被响应后执行,回调函数的参数为服务器的响应对象 res,创建的客户端通过 end 方法将请求发出与服务端进行通信。
使用 NodeJS 实现的 “爬虫” 其实就可以通过 http 模块创建的客户端来实现,客户端帮我们向我们要抓取数据的地址发送请求,并拿到响应的数据进行解析。
同时使用 HTTP 客户端和服务器
我们使用自己创建的客户端访问自己的服务端,并体会请求响应的过程,就是用上面 client.js 作为客户端,启动 server.js 后再启动 client.js 查看效果。
// 服务器:server.js const http = require("http"); http.createServer(function(req, res) { console.log("The request came"); // 获取客户端请求信息 console.log(req.method); console.log(req.headers); // 返回数据 res.write("hello world"); }).listen(3000, function() { console.log("server start 3000"); });
简易爬虫
我们结合 http 模块创建的服务端和客户端实现一个简易版的 “爬虫” 去抓取百度新闻页所有 li 标签内的文章标题。
// 简易爬虫:crawl.js const http = require("http"); // 创建服务器 const server = http.createServer(); // 监听请求 server.on("request", function(req, res) { let client = http.request( { host: "news.baidu.com", method: "get", port: 80 }, function(r) { // 接收百度新闻返回的数据 let arr = []; r.on("data", function(data) { arr.push(data); }); r.on("end", function() { // 处理数据 let result = Buffer.concat(arr).toString(); let matches = result.match(/<li>([\s\S*?])<\/li>/gm); // 设置返回给浏览器的文档类型和编码格式 res.setHeader("Content-Type", "text/html;charset=utf8"); // 响应浏览器 res.end(matches.join("")); }); } ); client.end(); }); server.listen(3000);
上面的正则匹配中 ([\s\S*?]) 代表匹配 <li> 到 <\/li> 之间所有内容(多个字符、非贪婪模式),gm 代表全局并多行匹配。
上面爬取百度新闻数据的过程中,我们自己的 Node 服务器扮演了一个 “中间层” 的角色,我们通过浏览器访问自己的服务器 localhost:3000 触发 request 事件,执行了回调,在回调中创建客户端向 news.baidu.com 发送了请求,并在客户端的回调中处理了响应(百度新闻页返回的数据),将处理后的内容通过我们自己 Node 服务器的 res 对象返回给了浏览器。
总结
相信在读过本篇文章之后对搭建一个 Node 服务应该已经有了思路,为未来通过 Node 服务实现复杂的业务场景及数据的处理打下了一个基础,希望初学 Node 的小伙伴在看了这篇文章后能有所收获。