原文: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';

两者差不多,差异点在于

  1. res.writeHead() 可以提供额外的功能,比如设置响应头部。
  2. 当响应头部发送出去后,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');

两者的差异点在哪里呢?

  1. res.writeHead() 不单单是设置header。
  2. 已经通过 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 这里想下更好的解释。。。)

使用上没什么难度,只是有些注意事项:

  1. 如果 res.write() 被调用时, res.writeHead() 还没被调用过,那么,就会把header flush出去。
  2. res.write() 可以被调用多次。
  3. 当 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)的更多相关文章

  1. NodeJS学习笔记 (9)网络服务-https(ok)

    模块概览 这个模块的重要性,基本不用强调了.在网络安全问题日益严峻的今天,网站采用HTTPS是个必然的趋势. 在nodejs中,提供了 https 这个模块来完成 HTTPS 相关功能.从官方文档来看 ...

  2. NodeJS学习笔记 (8)网络服务-http-server(ok)

    http服务端概览 创建server 几行代码搞定 var http = require('http'); var requestListener = function(req, res){ res. ...

  3. NodeJS学习笔记 (5)网络服务-http-req(ok)

    原文:https://github.com/chyingp/nodejs-learning-guide 自己敲代码: 概览 本文的重点会放在req这个对象上.前面已经提到,它其实是http.Incom ...

  4. NodeJS学习笔记 (7)网络服务-http-client(ok)

    原文:https://github.com/chyingp/nodejs-learning-guide 自己敲代码: ClientRequest概览 当你调用 http.request(options ...

  5. NodeJS学习笔记 (4)网络服务-http(ok)

    原文:https://github.com/chyingp/nodejs-learning-guide 自己敲代码: http模块概览 大多数nodejs开发者都是冲着开发web server的目的选 ...

  6. nodejs学习笔记之网络编程

    了解一下OSI七层模型   OSI层 功能 TCP/IP协议 应用层 文件传输,电子邮件,文件服务,虚拟终端  TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 表示层 数据格式化 ...

  7. NodeJS学习笔记 (10)网络TCP-net(ok)

    模块概览 net模块是同样是nodejs的核心模块.在http模块概览里提到,http.Server继承了net.Server,此外,http客户端与http服务端的通信均依赖于socket(net. ...

  8. NodeJS学习笔记 (12)网络地址解析-url(ok)

    模块概述 nodejs中,提供了url这个非常实用的模块,用来做URL的解析.在做node服务端的开发时会经常用到.使用很简单,总共只有3个方法. 正式讲解前,各位同学先把下面这个图记在心上(来自no ...

  9. NodeJS学习笔记 (11)网络UDP-dgram(ok)

    模块概览 dgram模块是对UDP socket的一层封装,相对net模块简单很多,下面看例子. UPD客户端 vs UDP服务端 首先,启动UDP server,监听来自端口33333的请求. se ...

随机推荐

  1. Java回忆录之英勇黄铜V

    说实话最近心好累,就因为一个混合app开发贼简单的一个功能.我本以为很简单,做起来却发现需要很多知识面.麻雀虽小五脏俱全,即使再小的一个功能实现起来也需要很全面的知识来担保.要想盖高楼大厦啊必定要有坚 ...

  2. node——由新闻列表跳转到新闻详情页

    当我们在浏览新闻列表页面的时候,想要看感兴趣的新闻内容,需要到详情页面去查看内容. 在之前写好了新闻列表页面,现在需要做列表页面到详情页面的跳转,需要考虑一下问题 1.点击新闻列表某一项跳转到详情页面 ...

  3. UVA1583-Digit Generator(紫书例题3.5)

    For a positive integer N , the digit-sum of N is defined as the sum of N itself and its digits. When ...

  4. [luogu1772 ZJOI2006] 物流运输 (最短路 线性dp)

    题目描述 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪. ...

  5. [JZOJ]100047. 【NOIP2017提高A组模拟7.14】基因变异

    21 世纪是生物学的世纪,以遗传与进化为代表的现代生物理论越来越多的 进入了我们的视野. 如同大家所熟知的,基因是遗传因子,它记录了生命的基本构造和性能. 因此生物进化与基因的变异息息相关,考察基因变 ...

  6. idea 编辑器 光标问题!(insert键)

    今天写代码不小心按了键盘的insert键,光标莫名闪退了 ,重新打开的时候发现 光标变成了  按了insert 的效果  ,简直无语的要命啊! 这敲代码太恶心了!怒搜资料 结果找到了解决办法! 1.打 ...

  7. SQL SERVER-数据库的远程访问解决办法

    除了下面的这个RemoteDacEnabled更改为true之后,还要把防火墙关闭,才能通过IP地址访问数据库 来自为知笔记(Wiz)

  8. dubbo标签

    <dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心. <dubbo:reference/&g ...

  9. 暑假NOIP期末考试【1】—— Phantom

    Phantom •题目名称: phantom •时间限制:1 秒 •空间限制:256 MiB 题目描写叙述 在一个无限大的棋盘上.排列着 n * n 枚棋子,形成一个 n 行 n 列的方阵.棋子能够横 ...

  10. aliyun Ubuntu 14.04 64bit OpenJDK Tomcat7 install

    my work environment: aliyun Ubuntu 14.04 64位 first phase:apt-get update    (it is very important,oth ...