文章目录

  • 简介
  • 使用nodejs创建HTTP服务
  • 解构request
  • 处理Request Body
  • 处理异常
  • 解构response

简介

我们已经知道如何使用nodejs搭建一个HTTP服务,今天我们会详细的介绍nodejs中的HTTP处理流程,从而对nodejs的HTTP进行深入的理解。

使用nodejs创建HTTP服务

使用nodejs创建HTTP服务很简单,nodejs提供了专门的HTTP模块,我们可以使用其中的createServer方法来轻松创建HTTP服务:

const http = require('http');const server = http.createServer((request, response) => {// magic happens here!
});

首先createServer方法传入的是一个callback函数,这个callback函数将会在每次服务端接收到客户端的请求时调用。所以这个callback函数,也叫做 request handler.

再看看createServer的返回值,createServer返回的是一个EventEmitter对象。

之前我们也介绍过了EventEmitter,它可以发送和接收事件,所以我们可以使用on来监听客户端的事件。

上面的代码相当于:

const server = http.createServer();
server.on('request', (request, response) => {// the same kind of magic happens here!
});

当发送request事件的时候,就会触发后面的handler method,并传入request和response参数。我们可以在这个handler中编写业务逻辑。

当然,为了让http server正常运行,我们还需要加上listen方法,来绑定ip和端口,以最终启动服务。

const hostname = '127.0.0.1'
const port = 3000server.listen(port, hostname, () => {console.log(`please visit http://${hostname}:${port}/`)
})

解构request

上面的request参数实际上是一个http.IncomingMessage对象,我们看下这个对象的定义:

    class IncomingMessage extends stream.Readable {constructor(socket: Socket);aborted: boolean;httpVersion: string;httpVersionMajor: number;httpVersionMinor: number;complete: boolean;/*** @deprecate Use `socket` instead.*/connection: Socket;socket: Socket;headers: IncomingHttpHeaders;rawHeaders: string[];trailers: NodeJS.Dict<string>;rawTrailers: string[];setTimeout(msecs: number, callback?: () => void): this;/*** Only valid for request obtained from http.Server.*/method?: string;/*** Only valid for request obtained from http.Server.*/url?: string;/*** Only valid for response obtained from http.ClientRequest.*/statusCode?: number;/*** Only valid for response obtained from http.ClientRequest.*/statusMessage?: string;destroy(error?: Error): void;}

通常我们需要用到request中的method,url和headers属性。

怎么从request中拿到这些属性呢?对的,我们可以使用ES6中解构赋值:

const { method, url } = request;const { headers } = request;
const userAgent = headers['user-agent'];

其中request的headers是一个IncomingHttpHeaders,它继承自NodeJS.Dict。

处理Request Body

从源码可以看出request是一个Stream对象,对于stream对象来说,我们如果想要获取其请求body的话,就不像获取静态的method和url那么简单了。

我们通过监听Request的data和end事件来处理body。

let body = [];
request.on('data', (chunk) => {body.push(chunk);
}).on('end', () => {body = Buffer.concat(body).toString();// at this point, `body` has the entire request body stored in it as a string
});

因为每次data事件,接收到的chunk实际上是一个Buffer对象。我们将这些buffer对象保存起来,最后使用Buffer.concat来对其进行合并,最终得到最后的结果。

直接使用nodejs来处理body看起来有点复杂,幸运的是大部分的nodejs web框架,比如koa和express都简化了body的处理。

处理异常

异常处理是通过监听request的error事件来实现的。

如果你在程序中并没有捕获error的处理事件,那么error将会抛出并终止你的nodejs程序,所以我们一定要捕获这个error事件。

request.on('error', (err) => {// This prints the error message and stack trace to `stderr`.console.error(err.stack);
});

解构response

response是一个http.ServerResponse类:

    class ServerResponse extends OutgoingMessage {statusCode: number;statusMessage: string;constructor(req: IncomingMessage);assignSocket(socket: Socket): void;detachSocket(socket: Socket): void;// https://github.com/nodejs/node/blob/master/test/parallel/test-http-write-callbacks.js#L53// no args in writeContinue callbackwriteContinue(callback?: () => void): void;writeHead(statusCode: number, reasonPhrase?: string, headers?: OutgoingHttpHeaders): this;writeHead(statusCode: number, headers?: OutgoingHttpHeaders): this;writeProcessing(): void;}

对于response来说,我们主要关注的是statusCode:

response.statusCode = 404;

Response Headers:

response提供了setHeader方法来设置相应的header值。

response.setHeader('Content-Type', 'application/json');
response.setHeader('X-Powered-By', 'bacon');

还有一个更加直接的同时写入head和status code:

response.writeHead(200, {'Content-Type': 'application/json','X-Powered-By': 'bacon'
});

最后,我们需要写入response body,因为response是一个WritableStream,所以我们可以多次写入,最后以end方法结束:

response.write('<html>');
response.write('<body>');
response.write('<h1>Hello, World!</h1>');
response.write('</body>');
response.write('</html>');
response.end();

或者我们可以用一个end来替换:

response.end('<html><body><h1>Hello, World!</h1></body></html>');

综上,我们的代码是这样的:

const http = require('http');http.createServer((request, response) => {const { headers, method, url } = request;let body = [];request.on('error', (err) => {console.error(err);}).on('data', (chunk) => {body.push(chunk);}).on('end', () => {body = Buffer.concat(body).toString();// BEGINNING OF NEW STUFFresponse.on('error', (err) => {console.error(err);});response.statusCode = 200;response.setHeader('Content-Type', 'application/json');// Note: the 2 lines above could be replaced with this next one:// response.writeHead(200, {'Content-Type': 'application/json'})const responseBody = { headers, method, url, body };response.write(JSON.stringify(responseBody));response.end();// Note: the 2 lines above could be replaced with this next one:// response.end(JSON.stringify(responseBody))// END OF NEW STUFF});
}).listen(8080);

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/nodejs-http-in-depth/

本文来源:flydean的博客

欢迎关注我的公众号:「程序那些事」最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

深入理解nodejs的HTTP处理流程相关推荐

  1. linux内核led驱动开发,从Linux内核LED驱动来理解字符设备驱动开发流程

    目录 博客说明 开发环境 1. Linux字符设备驱动的组成 1.1 字符设备驱动模块加载与卸载函数 1.2 字符设备驱动的file_operations 结构体中的成员函数 2. 字符设备驱动--设 ...

  2. 深入理解nodejs中的异步编程

    文章目录 简介 同步异步和阻塞非阻塞 javascript中的回调 回调函数的错误处理 回调地狱 ES6中的Promise 什么是Promise Promise的特点 Promise的优点 Promi ...

  3. 理解nodejs中函数的参数的来由

    看一段创建并启动nodejs服务的代码,如下: var http = require('http');http.createServer(function (request, response) {r ...

  4. 【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程...

    上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本篇就针对第一个思考问题详细的讲解下Ids4是如何生成acce ...

  5. 深度学习算法训练和部署流程介绍--让初学者一篇文章理解算法训练和部署流程

    目录 1 什么是深度学习算法 2 算法训练 2.1 训练的原理 2.2 名词解释 3 算法C++部署 3.1 嵌入式终端板子部署 3.3.1 tpu  npu推理 3.3.2 cpu推理 3.2 服务 ...

  6. 重新理解Linux交叉编译及编译流程

    参考书籍 1.编译原理 2.嵌入式Linux应用开发 文章目录 一.交叉编译背景 二.gcc和arm-linux-gcc的常用选项 1.查询gcc帮助 2.常用gcc选项介绍 3.生成一个可执行文件的 ...

  7. 从煎鸡蛋的角度理解编程的思维和流程,你适合学吗?

    其实很多门外人对编程都是懵懵懂懂的,我们可以先看一张图来理解一下: [思维]就是程序员需要考虑到的各种需求,也就是我们想让计算机帮助我们实现什么. [表达]就是计算机可以看懂的指令也就是0和1. 那怎 ...

  8. 理解Nodejs的单线程实现高并发原理

    组成和架构 Nodejs 的特点是事件驱动.非阻塞I/O.高效.轻量. 我们首先看下 Nodejs 的架构. 最上层的是 Nodejs标准库,由JavaScript实现的api库,位置在 lib 目录 ...

  9. (翻译)理解NodeJs?

    (原文地址 作者: Felix Geisendörfer) 我推荐Node.js给别人,通常得到两种反应:要么恍然大悟,要么感到很困惑. 如果你是第二类人,我尝试着解释一下什么是Node: 命令行工具 ...

最新文章

  1. php和python写爬虫-一个简单的Python写的XML爬虫
  2. 程序员的十层楼(第11层)
  3. 贪心算法之买卖股票的最佳时机 II
  4. linux下如何产生core,调试core
  5. Mac OSX中memcached安装测试
  6. wpf开源ui引用步骤_如何通过7个步骤开源您的学术作品
  7. RBAC用户角色权限设计方案(转)
  8. 【数据库】sql连表查询
  9. 解决docker-compose: command not found
  10. php连接sql server
  11. 11计算机专业vb试题答案,11计算机专业VB试题(二).doc
  12. 【备忘】最新区块链开发入门到精通视频教程下载
  13. selenium爬取淘宝评论信息
  14. 霹雳吧啦Wz语义分割学习笔记P4
  15. 测序深度和覆盖度(Sequencing depth and coverage)
  16. 数据驱动测试一:使用TestNG进行数据驱动
  17. Java计算文章多少字_java计算中文字数的代码实例
  18. SCI (SSCI) 投稿全过程信件模板一览(Cover letter,催稿信,修改稿及回复,感谢信,询问校稿及校稿信) (转)
  19. 微信小程序 系统复制粘贴文本
  20. 使用C#启动默认Internet浏览器

热门文章

  1. TensorFlow2-循环神经网络
  2. HDU4259(简单群置换)
  3. 用 GetEnvironmentVariable 获取常用系统环境变量
  4. ADO学习(三)Command 对象
  5. GlobalAlloc全局内存的使用
  6. 原始 H.264 码流播放
  7. python中内置的数据结构有几种?
  8. Spectre CPU漏洞借着BPF春风卷土重来
  9. 消息中间件(Kafka/RabbitMQ)收录集
  10. Go udp 的高性能优化