zoukankan      html  css  js  c++  java
  • http模块中的writeHead

    writeHead

    response.writeHead(statusCode[, statusMessage][, headers])
    statusMessage 好像没什么用,一般用不到。
    返回对 ServerResponse 的引用,以便可以链式调用。

    const body = 'hello world';
    response
      .writeHead(200, {
        'Content-Length': Buffer.byteLength(body),
        'Content-Type': 'text/plain'
      })
      .end(body);
    

    如果在调用writeHead之前调用了 response.write() 或 response.end(),会报错。

    net::ERR_INVALID_CHUNKED_ENCODING
    

    当使用 response.setHeader() 设置响应头时,则与传给 response.writeHead() 的任何响应头合并,且 response.writeHead() 的优先。

    res.setHeader('X-Foo', 'bar');
    res.writeHead(200, { 'X-Foo': 'bar11' });
    console.log(res.getHeader('Content-Type') ); // bar11
    

    调用writeHead之后调用setHeader,报错:

    Cannot set headers after they are sent to the client
    
    // 在源代码中有如下的定义,这里是报错的地方
    OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
      if (this._header) {
        throw new ERR_HTTP_HEADERS_SENT('set');
      }
    }
    

    如果调用此方法并且尚未调用 response.setHeader(),则直接将提供的响应头值写入网络通道而不在内部进行缓存,响应头上的 response.getHeader() 将不会产生预期的结果。

    response.writeHead(200, { 'Content-Type': 'text/plain' });
    console.log(response.getHeader('Content-Type') ); // undefined
    // 没有内部缓存导致获取不到刚刚设置的'content-type'
    

    对比先调用response.setHeader,再调用writeHead:

    res.setHeader('X-Foo', 'bar');
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    console.log(res.getHeader('Content-Type') ); // 'text/plain'
    // 可以获取到刚刚设置的content-type
    

    如果需要渐进的响应头填充以及将来可能的检索和修改,则改用 response.setHeader()。

    // 返回 content-type = text/plain
    const server = http.createServer((req, res) => {
      res.setHeader('Content-Type', 'text/html');
      res.setHeader('X-Foo', 'bar');
      res.writeHead(200, { 'Content-Type': 'text/plain' });
      res.end('ok');
    });
    

    之前在遇到一个问题:

    代码中只是重新定义了res.writeHead,在向客户端返回数据的时候会自动调用res.writeHead,问题在于代码中并没有调用writeHead ?

    var http = require('http')
    var server  = http.createServer(function (req,res) {
        var _ = res.writeHead
        res.writeHead = function(...arg){
            console.log(arg);
            _.call(this,arg)
        }
        res.write('adfasdfsf') // 调用write会触发writeHead
        res.end()
    })
    server.listen(10899,function () {
        console.log(121212);
    })
    

    通过断点跟踪发现有如下的逻辑链条:

    ObjectSetPrototypeOf(ServerResponse.prototype, OutgoingMessage.prototype);// 原型继承,response上面的部分方法继承自OutgoingMessage
    
    // write方法,当调用response.write的时候就是调用的这里
    OutgoingMessage.prototype.write = function write(chunk, encoding, callback) {
      const ret = write_(this, chunk, encoding, callback, false);
      if (!ret)
        this[kNeedDrain] = true;
      return ret;
    };
    
    function write_(msg, chunk, encoding, callback, fromEnd) {
      if (!msg._header) {
        msg._implicitHeader();
      }
    }
    
    // 调用writeHead,所以只要执行write方法就会调用writeHead方法	
    ServerResponse.prototype._implicitHeader = function _implicitHeader() {
      this.writeHead(this.statusCode);
    };
    
    ServerResponse.prototype.writeHead = writeHead;
    function writeHead(statusCode, reason, obj) {}
    

    同样在在调用response.end的时候也有类似的处理:

    ServerResponse.prototype.end继承自OutgoingMessage.prototype.end
    
    OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
     ......
      if (chunk) {
     		.........
        write_(this, chunk, encoding, null, true);
      } else if (this.finished) {
        ......
      } else if (!this._header) {
        this._contentLength = 0;
        this._implicitHeader();
      }
    }
    // 如果传入了第一个参数,调用write_,接下来就是上面的步骤
    // 如果没有传入参数,并且没有header,直接调用了_implicitHeader,其实就是this.writeHead(this.statusCode);
    
  • 相关阅读:
    react 有多个按钮时点击单个按钮独立控制Loading
    React路由通信
    体育竞技模拟比赛
    json与csv格式相互转换
    替换表格内容及csv转html及CGI
    excel转换成csv格式
    文件读写笔记
    自定义手绘风
    numpy&matplotlib读书笔记
    Python成绩雷达图
  • 原文地址:https://www.cnblogs.com/walkermag/p/13586901.html
Copyright © 2011-2022 走看看