原文: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. C++中static和const关键字的作用

    static关键字至少有下列几个作用: 函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值: 在模块内的static全局变量 ...

  2. NSPort与NSRunloop的关系是流与消息调度的关系

    NSPort与NSRunloop的关系是流与消息调度的关系. NSPort 将流插入到消息调度队列: 相当于 Socket将流插入到应用一样 - (void)launchThread { NSPort ...

  3. Django中ORM之查询表记录

    查询相关API from django.db import models # Create your models here. class Book(models.Model): title = mo ...

  4. spring-session与redis实现session共享

    一.准备 两个不同端口号的输出request.getLocalPort() + " ---> " + request.getSession(true).getId()的简单S ...

  5. ubuntu12.04开启Framebuffer

    一.framebuffer概述 Framebuffer在Linux中是作为设备来实现的,它是对图形硬件的一种抽象,代表着显卡中的帧缓冲区(Framebuffer).通过Framebuffer设备,上层 ...

  6. [terry笔记]python FTP

    如下是作业,用python做一个ftp,主要利用socket. server端在linux下运行,在client端可以执行shell命令(静态的) 在client端输入get xxx,即可下载. 在c ...

  7. synchronized的实现原理及锁优化

    记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized.对于当时的我们来说,synchronized是如此的神奇且强大.我们赋予它一个名字“同步”,也成为我们解决多线程情况的良药 ...

  8. linux内核(三)文件系统

    1.为什么需要根文件系统 (1)init进程的应用程序在根文件系统上(2)根文件系统提供了根目录/(3)内核启动后的应用层配置(etc目录)在根文件系统上.几乎可以认为:发行版=内核+rootfs(4 ...

  9. 求第K大的数字

    除了用最大堆(求最小的K个数)或最小堆(求最大的K个数) 可以用partition,然后直到返回index为k为止.参数可以是实际下标.然后返回index,就是partition的pivot的位置.

  10. git batch

    git batch 不用每次自己写了:不是特别推荐哦: git add . git commit -m "commit" git push git status