天天看点

[NODE之15]http 原生response

/**
 * Created by liyanq on 17/3/29.
 * http.ServerResponse 类
 * 这个类非常重要,是给客户端的数据的重要通道。
 * 计划分两部分:原生的对象和express框架下的对象。
 */

/*原生对象
 注意要点
 * 1,该对象是由一个 HTTP 服务器(而不是用户)内部创建的。所以不用new一个对象。
 * 2,该响应实现(而不是继承自)[可写流]接口。
 * 3,继承:res:ServerResponse->OutgoingMessage->Stream->EventEmitter*/
/*事件
 * 1,'close' 事件:表明在 response.end() 被调用或能够刷新之前,底层连接被终止了。
 * 2,'finish' 事件:当响应已被发送时触发。
 * 更具体地说,当响应头和主体的最后一部分已被交给操作系统通过网络进行传输时,触发该事件。
 * 这并不意味着客户端已接收到任何东西。该事件触发后,响应对象上不再触发其他事件。
 *
 * */


/*方法
 * 1,response.addTrailers(headers)->相当于预留个位置,一般用不到
 * 该方法会给响应添加 HTTP 追踪请求头(一个在消息尾部的请求头)。
 * 追踪仅当响应使用分块编码时才会被发送;如果不是(比如请求是 HTTP/1.0),则它们将被丢弃。
 * 注意,如果想要发送追踪,则 HTTP 要求发送 Trailer 请求头,且在值里带上请求头字段的列表。
 *
 * 解释:
 * Transfer-Encoding: chunked
 * Trailer: XXXXX
 *
 * 这个header有关,根据http1.1协议,当response的Transfer-Encoding为chunked时,
 * 允许在消息体后面附加其它的Header, 这个附加的Header就叫Trailers。
 *
 * 我们知道一般的http请求回应时,先是发送Headers(消息头), 再是发送body(消息体)。
 * 但是有些情况下,消息头需要与消息体有关联,比如需要在header里附上消息体的Hash签名,
 * 但是消息体并不总是预先就存在的,在动态产生消息体的情况下,如果在消息体产生完后再签好名,
 * 发送Headers和Body, 性能肯定会受影响。
 *
 * 比较好的做法是,Server获得请求后,开始发送可以发送的Headers,
 * 同时设置Transfer-Encoding: chunked, Trailer: XXXX。
 * 然后对动态产生的消息体一个chunk,一个chunk的发,发完以后,再附加上Hash头。
 *
 * 2,response.end([data][, encoding][, callback])->encoding好像不好用,得用header的Content-Type设置编码格式。
 * data <String> | <Buffer>
 * encoding <String>
 * callback <Function>
 *
 * 该方法告诉服务器所有响应头和主体都已被发送;
 * 服务器应将消息视为已完成。 对于每个响应,response.end() 方法必须被调用。
 * 如果指定了 data,则它等同于调用 response.write(data, encoding) 之后调用 response.end(callback)。
 *
 * 3,response.getHeader(name)->必须与setHeader配合使用,直接通过writeHeader写的头信息读不到~
 *   读出已经排队但尚未发送到客户端的消息头。 注意,名称不区分大小写。
 *
 * 4,response.headersSent->write执行后,为 true;
 *   如果消息头已被发送则为 true,否则为 false;
 *
 * 5,response.sendDate
 * 默认为 true。这应该只在测试中才被禁用;HTTP 需要响应日期消息头。
 *
 * 6,response.setHeader(name, value) ->需要注意的是,writeHead写完后,setHeader就不能用了,否则报错。
 *   当消息头已使用 response.setHeader() 设置,
 *   它们会被与其他消息头合并传给 response.writeHead(),带消息头的 response.writeHead() 有更高优先级。
 *
 * 7,response.statusCode->虽然状态码能被浏览器识别,但数据还是写过去了。
 * 当使用隐式的消息头时(没有显式地调用 response.writeHead()),在消息头被刷新时该属性会控制将被发送到客户端的状态码。
 *
 * 8,response.statusMessage->不能中文,在浏览器里面能看到~
 * 当使用隐式的消息头时(没有显式地调用 response.writeHead()),在消息头被刷新时该属性会控制将被发送到客户端的状态信息。 如果该值为 undefined,则使用状态码的标准信息。
 *
 * 9,response.write(chunk[, encoding][, callback])
 * 这是原始的 HTTP 主体,且与可能使用的更高级别的多部分主体编码无关。
 * response.write() 首次被调用时,它会发送缓冲的头信息和第一块主体到客户端。
 * response.write() 第二次被调用时,Node.js 会假定你要流化数据,并将它们分别发送。
 * 响应会被缓冲到主体的第一个数据块。
 *
 * */
const http = require("http");
const fs = require("fs");
const hostname = '127.0.0.1';


var server = http.createServer(function (req, res) {
    res.on("close", function () {//用网页请求,没有发生该事件,
        console.log("res.Close事件发生了~")
    });
    res.on("finish", function () {
        console.log("res.finish事件发生了~")
    });


    // res.writeHead(200, {
    //     'Content-Type': 'text/plain',
    //     'Trailer': 'Content-MD6',
    //     "Transfer-Encoding": "chunked"
    // });

    res.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
    res.setHeader("Server","Server");//能够读取到
    res.setHeader("Content-Type", ["text/html;charset=UTF-8"]);
    /*
    * Content-Type设置的时候,注意中间的横线,上面设置完全是为了浏览器能识别中文。下面是对照表
    * http://tool.oschina.net/commons*/

    // res.writeHead(200, {'Set-Cookie': 'writeHead'});//如果上面不设置,那么getHeader也读不出来~

    /*
     console.log("Set-Cookie:" + res.getHeader("Set-Cookie"));//type=ninja,language=javascript
     console.log("response.headersSent:" + res.headersSent);//true
     console.log("response.sendDate:" + res.sendDate);//true
     console.log("res.finished:" + res.finished);//false*/

    res.statusCode = 200;
    res.statusMessage = "Connect Successful";
    res.setTimeout(1000, function () {
        res.statusCode = 404;
        res.statusMessage = 'not found library';
        res.end(Buffer.from("连接超时"));
    });
    res.write("Hello world");
    res.write("\n");

    /*
     console.log("response.headersSent:" + res.headersSent);//true*/

    res.addTrailers({'Content-MD6': '7895bf4b8828b55ceaf47747b4bca667'});
    res.end("完成响应");

    /*
     console.log("res.finished:" + res.finished);//true*/

});

server.listen(3000, hostname, function () {
    console.log(`服务器运行在 http://${hostname}:3000/`);
});

//------------------------------------------------------------------------//
/*服务器响应header的参数对照表*/
/*
Header	         解释	                                      示例
Accept-Ranges	 表明服务器是否支持指定范围请求及哪种类型的分段请求   Accept-Ranges: bytes
Age	             从原始服务器到代理缓存形成的估算时间(以秒计,非负) Age: 12
Allow	         对某网络资源的有效的请求行为,不允许则返回405       Allow: GET, HEAD
Cache-Control	 告诉所有的缓存机制是否可以缓存及哪种类型	        Cache-Control: no-cache
Content-Encoding web服务器支持的返回内容压缩编码类型。	            Content-Encoding: gzip
Content-Language 响应体的语言	                                    Content-Language: en,zh
Content-Length	 响应体的长度	                                    Content-Length: 348
Content-Location 请求资源可替代的备用的另一地址	                    Content-Location: /index.htm
Content-MD5	     返回资源的MD5校验值	                            Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
Content-Range	 在整个返回体中本部分的字节位置                  	Content-Range: bytes 21010-47021/47022
Content-Type	 返回内容的MIME类型	                            Content-Type: text/html; charset=utf-8
Date	         原始服务器消息发出的时间	                        Date: Tue, 15 Nov 2010 08:12:31 GMT
ETag	         请求变量的实体标签的当前值	                        ETag: “737060cd8c284d8af7ad3082f209582d”
Expires          响应过期的日期和时间                              Expires: Thu, 01 Dec 2010 16:00:00 GMT
Last-Modified	 请求资源的最后修改时间	                        Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
Location	     用来重定向接收方到非请求URL的位置来完成请求或标识新
                 的资源	                                        Location: http://www.zcmhi.com/archives/94.html
Pragma	         包括实现特定的指令,它可应用到响应链上的任何接收方	Pragma: no-cache
Proxy-Authenticate	它指出认证方案和可应用到代理的该URL上的参数	    Proxy-Authenticate: Basic
refresh	         应用于重定向或一个新的资源被创造,在5秒之后重定向
                (由网景提出,被大部分浏览器支持)                  Refresh: 5; url=http://www.zcmhi.com/archives/94.html
Retry-After	     如果实体暂时不可取,通知客户端在指定时间之后再次尝试	Retry-After: 120
Server	         web服务器软件名称	                            Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
Set-Cookie	     设置Http Cookie                             	Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
Trailer	         指出头域在分块传输编码的尾部存在	                Trailer: Max-Forwards
Transfer-Encoding文件传输编码	                                    Transfer-Encoding:chunked
Vary	         告诉下游代理是使用缓存响应还是从原始服务器请求       Vary: *
Via	             告知代理客户端响应是通过哪里发送的	                 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning	         警告实体可能存在的问题	                         Warning: 199 Miscellaneous warning
WWW-Authenticate 表明客户端请求实体应该使用的授权方案	             WWW-Authenticate: Basic
*/