NodeJS学习笔记 (6)网络服务-http-res(ok)
原文:https://github.com/chyingp/nodejs-learning-guide
自己敲代码:
概览
http模块四剑客之一的res
,应该都不陌生了。一个web服务程序,接受到来自客户端的http请求后,向客户端返回正确的响应内容,这就是res
的职责。
返回的内容包括:状态代码/状态描述信息、响应头部、响应主体。下文会举几个简单的例子。
- var http = require('http');
- var server = http.createServer(function(req, res){
- res.send('ok');
- });
- server.listen(3000);
例子
在下面的例子中,我们同时设置了 状态代码/状态描述信息、响应头部、响应主体,就是这么简单。
- var http = require('http');
- // 设置状态码、状态描述信息、响应主体
- var server = http.createServer(function(req, res){
- res.writeHead(200, 'ok', {
- 'Content-Type': 'text/plain'
- });
- res.end('hello');
- });
- server.listen(3000);
设置状态代码、状态描述信息
res
提供了 res.writeHead()、res.statusCode/res.statusMessage 来实现这个目的。
举例,如果想要设置 200/ok ,可以
- res.writeHead(200, 'ok');
也可以
- res.statusCode = 200;
- res.statusMessage = 'ok';
两者差不多,差异点在于
- res.writeHead() 可以提供额外的功能,比如设置响应头部。
- 当响应头部发送出去后,res.statusCode/res.statusMessage 会被设置成已发送出去的 状态代码/状态描述信息。
设置响应头部
res
提供了 res.writeHead()、response.setHeader() 来实现响应头部的设置。
举例,比如想把 Content-Type
设置为 text-plain
,那么可以
- // 方法一
- res.writeHead(200, 'ok', {
- 'Content-Type': 'text-plain'
- });
- // 方法二
- res.setHeader('Content-Type', 'text-plain');
两者的差异点在哪里呢?
- res.writeHead() 不单单是设置header。
- 已经通过 res.setHeader() 设置了header,当通过 res.writeHead() 设置同名header,res.writeHead() 的设置会覆盖之前的设置。
关于第2点差异,这里举个例子。下面代码,最终的 Content-Type
为 text/plain
。
- var http = require('http');
- var server = http.createServer(function(req, res){
- res.setHeader('Content-Type', 'text/html');
- res.writeHead(200, 'ok', {
- 'Content-Type': 'text/plain'
- });
- res.end('hello');
- });
- server.listen(3000);
而下面的例子,则直接报错。报错信息为 Error: Can't set headers after they are sent.
。
- var http = require('http');
- var server = http.createServer(function(req, res){
- res.writeHead(200, 'ok', {
- 'Content-Type': 'text/plain'
- });
- res.setHeader('Content-Type', 'text/html');
- res.end('hello');
- });
- server.listen(3000);
其他响应头部操作
增、删、改、查 是配套的。下面分别举例说明下,例子太简单就直接上代码了。
- // 增
- res.setHeader('Content-Type', 'text/plain');
- // 删
- res.removeHeader('Content-Type');
- // 改
- res.setHeader('Content-Type', 'text/plain');
- res.setHeader('Content-Type', 'text/html'); // 覆盖
- // 查
- res.getHeader('content-type');
其中略显不同的是 res.getHeader(name),name 用的是小写,返回值没做特殊处理。
- res.setHeader('Content-Type', 'TEXT/HTML');
- console.log( res.getHeader('content-type') ); // TEXT/HTML
- res.setHeader('Content-Type', 'text/plain');
- console.log( res.getHeader('content-type') ); // text/plain
此外,还有不那么常用的:
- res.headersSent:header是否已经发送;
- res.sendDate:默认为true。但为true时,会在response header里自动设置Date首部。
设置响应主体
主要用到 res.write() 以及 res.end() 两个方法。
res.write() API的信息量略大,建议看下官方文档。
response.write(chunk[, encoding][, callback])
- chunk:响应主体的内容,可以是string,也可以是buffer。当为string时,encoding参数用来指明编码方式。(默认是utf8)
- encoding:编码方式,默认是 utf8。
- callback:当响应体flushed时触发。(TODO 这里想下更好的解释。。。)
使用上没什么难度,只是有些注意事项:
- 如果 res.write() 被调用时, res.writeHead() 还没被调用过,那么,就会把header flush出去。
- res.write() 可以被调用多次。
- 当 res.write(chunk) 第一次被调用时,node 会将 header 信息 以及 chunk 发送到客户端。第二次调用 res.write(chunk) ,node 会认为你是要streaming data(WTF,该怎么翻译)。。。
Returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in user memory. 'drain' will be emitted when the buffer is free again.
response.end([data][, encoding][, callback])
掌握了 res.write() 的话,res.end() 就很简单了。res.end() 的用处是告诉nodejs,header、body都给你了,这次响应就到这里吧。
有点像个语法糖,可以看成下面两个调用的组合。至于callback,当响应传递结束后触发。
- res.write(data, encoding);
- res.end()
chunk数据
参考这里:http://stackoverflow.com/questions/6258210/how-can-i-output-data-before-i-end-the-response
也就是说,除了nodejs的特性,还需要了解 HTTP协议、浏览器的具体实现。(细思极恐)
如果是 text/html
- var http = require('http');
- http.createServer(function(req, res) {
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
- res.write('hello');
- setTimeout(function() {
- res.write(' world!');
- res.end();
- }, 2000);
- }).listen(3000);
如果是 text/plain
- var http = require('http');
- http.createServer(function (req, res) {
- res.writeHead(200, {
- 'Content-Type': 'text/plain; charset=utf-8',
- 'X-Content-Type-Options': 'nosniff'
- });
- res.write('hello');
- setTimeout(function(){
- res.write('world');
- res.end()
- }, 2000);
- }).listen(3000);
失败例子
- var http = require('http');
- var server = http.createServer(function(req, res){
- res.writeHead(200, 'ok', {
- 'Content-Type': 'text/html'
- });
- res.write('hello');
- setTimeout(function(){
- res.write('world');
- res.end();
- }, 2000);
- });
- server.listen(3000);
超时处理
接口:response.setTimeout(msecs, callback)
关于 timeout 事件的说明,同样是言简意赅(WTF),话少信息量大,最好来个demo TODO
If no 'timeout' listener is added to the request, the response, or the server, then sockets are destroyed when they time out. If you assign a handler on the request, the response, or the server's 'timeout' events, then it is your responsibility to handle timed out sockets.
事件 close/finish
- close:response.end() 被调用前,连接就断开了。此时会触发这个事件。
- finish:响应header、body都已经发送出去(交给操作系统,排队等候传输),但客户端是否实际收到数据为止。(这个事件后,res 上就不会再有其他事件触发)
其他不常用属性/方法
- response.finished:一开始是false,响应结束后,设置为true。
- response.sendDate:默认是true。是否自动设置Date头部。(按HTTP协议是必须要的,除非是调试用,不然不要设置为false)
- response.headersSent:只读属性。响应头部是否已发送。
- response.writeContinue():发送 HTTP/1.1 100 Continue 消息给客户端,提示说服务端愿意接受客户端的请求,请继续发送请求正文(body)。(TODO 做个demo啥的是大大的好)
相关链接
How can I output data before I end the response? http://stackoverflow.com/questions/6258210/how-can-i-output-data-before-i-end-the-response
8.2.3 Use of the 100 (Continue) Status http://greenbytes.de/tech/webdav/rfc2616.html#use.of.the.100.status
NodeJS学习笔记 (6)网络服务-http-res(ok)的更多相关文章
- NodeJS学习笔记 (9)网络服务-https(ok)
模块概览 这个模块的重要性,基本不用强调了.在网络安全问题日益严峻的今天,网站采用HTTPS是个必然的趋势. 在nodejs中,提供了 https 这个模块来完成 HTTPS 相关功能.从官方文档来看 ...
- NodeJS学习笔记 (8)网络服务-http-server(ok)
http服务端概览 创建server 几行代码搞定 var http = require('http'); var requestListener = function(req, res){ res. ...
- NodeJS学习笔记 (5)网络服务-http-req(ok)
原文:https://github.com/chyingp/nodejs-learning-guide 自己敲代码: 概览 本文的重点会放在req这个对象上.前面已经提到,它其实是http.Incom ...
- NodeJS学习笔记 (7)网络服务-http-client(ok)
原文:https://github.com/chyingp/nodejs-learning-guide 自己敲代码: ClientRequest概览 当你调用 http.request(options ...
- NodeJS学习笔记 (4)网络服务-http(ok)
原文:https://github.com/chyingp/nodejs-learning-guide 自己敲代码: http模块概览 大多数nodejs开发者都是冲着开发web server的目的选 ...
- nodejs学习笔记之网络编程
了解一下OSI七层模型 OSI层 功能 TCP/IP协议 应用层 文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 表示层 数据格式化 ...
- NodeJS学习笔记 (10)网络TCP-net(ok)
模块概览 net模块是同样是nodejs的核心模块.在http模块概览里提到,http.Server继承了net.Server,此外,http客户端与http服务端的通信均依赖于socket(net. ...
- NodeJS学习笔记 (12)网络地址解析-url(ok)
模块概述 nodejs中,提供了url这个非常实用的模块,用来做URL的解析.在做node服务端的开发时会经常用到.使用很简单,总共只有3个方法. 正式讲解前,各位同学先把下面这个图记在心上(来自no ...
- NodeJS学习笔记 (11)网络UDP-dgram(ok)
模块概览 dgram模块是对UDP socket的一层封装,相对net模块简单很多,下面看例子. UPD客户端 vs UDP服务端 首先,启动UDP server,监听来自端口33333的请求. se ...
随机推荐
- jsp+jdbc实现用户登录
1.1 创建数据库表 表名:user 字段: userid 保存用户的登录id name 用户名 password 密码 1.2 实现思路 a. 用户登录,则需要有个一个表单页,此页面可输 ...
- Vue学习之路第九篇:双向数据绑定 v-model指令
1.学习准备: ①:双向数据绑定可以简单理解为:后端定义的数据改变,前端页面展示的时候会自动改变,数据通过前端页面修改的时候,后端定义的数据内容也会随之改变. ②:指令中只有v-model可以实现双向 ...
- event 下鼠标坐标的获取
event.clientX.event.clientY 鼠标相对于浏览器窗口可视区域的X,Y坐标(窗口坐标),可视区域不包括工具栏和滚动条.IE事件和标准事件都定义了这2个属性 event.pageX ...
- rsync实时同步mysql数据库
1.主机slave 注:没有包的可以去下载 yum -y install gcc gcc-c++ 上传包 rsync-3.1.3.tar.gz 使用tar命令解压 使用gcc gcc-c++编译 ./ ...
- ansible 定义主机用户和密码
定义主机组用户和密码 [webservers] ansible[01:04] ansible_ssh_user='root' ansible_ssh_pass='AAbb0101' [root@ftp ...
- 转载一遍比较好的,django2.1搭建博客教程
非常感谢这位博主,找了几个星期终于找到了 https://www.dusaiphoto.com/article/article-detail/4/
- dfs序题集
dfs序可以维护一个子树内的信息 需要记录dfs进的时间以及所有子树都遍历完的时间 void dfs(int u, int fa) { L[u] = ++id; for(int i = head[u] ...
- (转载)springboot集成httpinvoker的客户端
原文:https://blog.csdn.net/geanwan/article/details/51505679 由于新项目采用了springboot,需要调用之前远程服务(之前项目用的spring ...
- C#-C#6.0新特性
来自为知笔记(Wiz)
- Xdoclet + Ant自己主动生成Hibernate配置文件
在使用Hibernate的时候,过多的Hibernate配置文件是一个让人头疼的问题. 近期接触了Xdoclet这个工具. 它实际上就是一个自己主动代码生成的工具.Xdoclet不能单独执行,必须搭配 ...