expressjs/express
Response
Active contributors: dougwilson, ulisesgascon, wesleytodd
Purpose
lib/response.js defines the res prototype attached to outgoing responses. It builds on http.ServerResponse.prototype and provides the bulk of the user-visible response API: status codes, body senders, JSON helpers, file streaming, redirects, content negotiation, cookie helpers, and view rendering.
At ~1,047 lines, it is the largest file in core.
Directory layout
lib/
└── response.js # this fileKey abstractions
Status and metadata
| Method | What it does |
|---|---|
res.status(code) |
Sets statusCode. Throws TypeError if not an integer, RangeError if outside [100, 999]. Express 5 strict mode. |
res.sendStatus(code) |
Status + the standard statuses.message[code] body, with text/plain content type. |
res.links(links) |
Builds the Link header from { rel: url } (supports arrays for multiple links per rel — added in 5.1). |
res.set(field, val) / res.header |
Header setter. Accepts an object form res.set({a: 1, b: 2}). Auto-injects charset on Content-Type. Arrays for Content-Type throw. |
res.get(field) |
getHeader shortcut. |
res.append(field, val) |
Appends to a header value, building an array when there's already a previous value. |
res.type(type) / res.contentType |
Sets Content-Type. Routes through mime.contentType() when no / is present; falls back to application/octet-stream. |
res.attachment(filename?) |
Sets Content-Disposition: attachment; filename=..., plus the type from the extension when a filename is given. |
res.vary(field) |
Adds to the Vary header (delegates to the vary package). |
res.location(url) |
Sets Location, encoding via encodeUrl. |
Bodies
| Method | What it does |
|---|---|
res.send(body) |
Sends a string/Buffer/object/boolean/number. Computes Content-Length, optionally generates ETag (when no existing ETag and etag fn set), respects req.fresh (becomes 304), and short-circuits to JSON for plain objects. Supports Uint8Array (added in 5.1). |
res.json(obj) |
Stringifies with json escape / json replacer / json spaces settings, sets Content-Type: application/json, calls res.send. |
res.jsonp(obj) |
JSON with a callback wrapper from req.query[jsonp callback name]. Adds X-Content-Type-Options: nosniff, escapes \u2028/\u2029, prepends /**/ to mitigate Rosetta Flash. |
res.sendFile(path, opts?, cb?) |
Streams a file via the send package. Throws TypeError if path is missing/non-string or relative without opts.root. Honours the app's 'etag' setting via opts.etag. (5.1 added explicit etag option.) |
res.download(path, name?, opts?, cb?) |
Sets Content-Disposition (via content-disposition) and delegates to sendFile. |
Redirects and rendering
| Method | What it does |
|---|---|
res.redirect([status,] url) |
Default status 302. Emits a text/plain body for text accept, an HTML body for HTML accept, or empty otherwise. undefined URL or non-string URL triggers a depd deprecation warning (5.2). |
res.render(view, opts?, cb?) |
Calls req.app.render with _locals = res.locals. If no callback, sends the rendered string; otherwise passes it through. |
res.format({ ... }) |
Content negotiation: matches a key against req.accepts(keys), sets the matching Content-Type, calls the matched function. Adds Vary: Accept. Falls back to default callback or next(createError(406, { types: ... })). |
Cookies
| Method | What it does |
|---|---|
res.cookie(name, value, opts?) |
Serialises via the cookie package. Supports signed: true (requires req.secret), object values (prefixed j: then JSON-stringified), and maxAge → expires translation. Defaults path to /. |
res.clearCookie(name, opts?) |
Sets a cookie with expires set to the past. Strips user-provided maxAge (Express 5 behaviour). |
Internal helpers
sendfile(res, file, options, callback)— wiressend's event stream to the response, handlesdirectory,error,aborted,finishevents with double-fire protection.stringify(value, replacer, spaces, escape)—JSON.stringifyplus optional HTML-escape pass for<,>,&.
How it works
res.send decision tree
graph TD
Send["res.send body"] --> Type{"typeof body"}
Type -- string --> Encoding["encoding=utf8;<br/>set Content-Type with charset<br/>or default to html"]
Type -- bool/num/null --> AsIs[treat as text-ish]
Type -- object/Buffer --> ObjBuf{"is ArrayBuffer view?"}
ObjBuf -- yes --> Bin["set type bin if no Content-Type"]
ObjBuf -- no --> ToJson["res.json body"]
Encoding --> Length[set Content-Length]
AsIs --> Length
Bin --> Length
Length --> ETag{"etagFn?<br/>and no ETag yet"}
ETag -- yes --> SetETag[res.set ETag]
ETag -- no --> Fresh{"req.fresh?"}
SetETag --> Fresh
Fresh -- yes --> Status304[status 304]
Fresh -- no --> CheckCode{"204 / 304 / 205?"}
Status304 --> CheckCode
CheckCode -- 204/304 --> Strip[strip body and Content-* headers]
CheckCode -- 205 --> SetZero[Content-Length 0, no Transfer-Encoding]
CheckCode -- other --> EndBody{"HEAD?"}
Strip --> EndBody
SetZero --> EndBody
EndBody -- yes --> EndNoBody[res.end]
EndBody -- no --> EndWithBody[res.end chunk]res.sendFile flow
sequenceDiagram
participant Caller
participant Res as res.sendFile
participant Send as send package
participant File as fs stream
participant Sock as response socket
Caller->>Res: res.sendFile(path, opts, cb)
Res->>Res: validate path + opts.root
Res->>Res: opts.etag = app.enabled('etag')
Res->>Send: send(req, encodeURI(path), opts)
Send->>File: open + stat
File->>Send: streamable
Send->>Res: emit 'file' / 'stream' / 'directory' / 'error'
Res->>Sock: file.pipe(res)
Sock-->>Res: onFinished -> onfinish
Res->>Caller: cb(err?) — guarded by `done` flagContent negotiation (res.format)
graph TD
Format[res.format obj] --> Keys[keys = Object.keys without default]
Keys --> Vary[res.vary 'Accept']
Vary --> Match[req.accepts keys]
Match --> Found{match?}
Found -- yes --> SetType[set Content-Type from normalizeType key]
SetType --> Call[obj key req,res,next]
Found -- no --> Default{obj.default?}
Default -- yes --> Run[obj.default req,res,next]
Default -- no --> Err[next createError 406, types]Integration points
- Imports:
content-disposition,http-errors,depd,encodeurl,escape-html,node:http,on-finished,mime-types,node:path,statuses,cookie-signature,./utils(normalizeType,normalizeTypes,setCharset),cookie,send,vary,node:buffer(Buffer). - Exposed via:
lib/express.jsexports it asexpress.response. Each app gets a per-app copy with.appset on it, attached toreson each request byapp.handle. - Reads from
app.settings:etag fn,json escape,json replacer,json spaces,jsonp callback name,'etag'(boolean shorthand for sendFile). - Used by: Every handler that produces a response.
Entry points for modification
- New body helper → mirror
res.send/res.json. Decide whether to callres.sendat the end (so ETag/freshness/HEAD are handled) or to write headers and end manually. - New file/streaming behaviour → modify
res.sendFileor thesendfilehelper. Be careful with thedoneflag — multiple events from thesendpackage can race. - Cookie option → extend
res.cookie. The bulk of validation is in thecookiepackage itself.
Key source files
| File | Purpose |
|---|---|
lib/response.js |
The res prototype |
lib/utils.js |
Content-type and charset helpers consumed here |
lib/application.js |
Wires app.response and provides app.render used by res.render |
Related pages
- Request — the symmetric prototype.
- Application — owns settings consumed by these helpers.
- Features / Body parsing — the inbound counterpart.
- Features / Templating — backs
res.render.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.