33

I use node.js and express at a small project. I set response header like blow:

res.set({'Content-Type':'text/plain;charset=utf-8',    
'Content-Length': Buffer.byteLength(data, 'utf-8')});       

I can use console.log print data's length is 317.

But at browser's console, I just get these:

Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/plain;charset=utf-8
Date:Sat, 01 Jun 2013 08:21:59 GMT
Transfer-Encoding:chunked
Vary:Accept-Encoding
X-Powered-By:Express

So, why the content-length disappeared?

Dmitry Minkovsky
  • 36,185
  • 26
  • 116
  • 160
Allen Heavey
  • 530
  • 2
  • 5
  • 16

1 Answers1

55

The response has Transfer-Encoding: chunked. Here Content-Length is not applicable, because the content is sent in one or more parts (chunks) inside the response body, with a marker indicating the byte-length of each individual chunk. http://en.wikipedia.org/wiki/Chunked_transfer_encoding

Node.js defaults to Transfer-Encoding: chunked. However, this is disabled by setting the Content-Length header on the native http response object. Documentation of HTTP module says:

Sending a 'Content-length' header will disable the default chunked encoding.

Going by the Content-Encoding:gzip header in your response, you probably have enabled the connect.compress middleware. The connect.compress middleware removes the Content-Length header.

In any case, unless you are generating gzipped content yourself, the Content-Length header you generate yourself would surely be inappropriate for the final (gzipped) response body. Luckily, the connect middleware takes care of that for you.

When using Express or Connect, you should not assume that the things you "send" with the res object actually get sent that way to the client. There's middleware in between. All middleware has the ability to change just about anything about the response, including changing the response body, and adding, removing and changing headers. Same goes for the request.

See also these questions:

Community
  • 1
  • 1
Myrne Stol
  • 11,222
  • 4
  • 40
  • 48
  • 3
    Sorry, I don't know who did this downvote, but you're right. Thank you very much. After comment `app.use(express.compress());`, content-length appears. But, can I use gzip and content-length both? – Allen Heavey Jun 01 '13 at 12:22
  • @DMDGeeker, in principle, yes, you can use `Transfer-Encoding: gzip` and `Content-Length` together. However, not with the `express.compress` middleware. It just doesn't support that. In principle, sending a Content-Length header is to be preferred if you can know the response length. You could compress content yourself or look for different "compression" middleware. But `Content-Length` must reflect the actual content sent. It must reflect the byte-length of the final (perhaps compressed) body. – Myrne Stol Jun 01 '13 at 12:26
  • The reason `connect.compress` does not add a new `Content-Length` to the response is that it would require buffering the compressed response body. Only when the buffer is complete can the content-length be known, after all. – Myrne Stol Jun 01 '13 at 12:37
  • If you gzip the buffer yourself using `zlib.gzip` and then do `res.set ({"Transfer-Encoding": "gzip"})`, the `connect.compress` middleware won't touch it. – Myrne Stol Jun 01 '13 at 12:43
  • Thank you. I will have a try. – Allen Heavey Jun 01 '13 at 12:47