public interface HttpResponse
An http response contains a status, some headers and cookies, and (in most cases) an entity.
An HttpResponse is sharable iff its entity is sharable. A sharable response can be cached and served to multiple requests.
See HttpResponseImpl
for a mutable implementation.
This interface contains some static methods for creating/transforming responses,
for example text(int, CharSequence...)
, gzip(HttpResponse)
.
Most of these methods return HttpResponseImpl
which the caller can modify. Note also that
HttpResponseImpl
is a subtype of Async<HttpResponse>
.
Example usage:
Async<HttpResponse> handle(HttpRequest request) { return HttpResponse .text(200, "goodbye world") // create a response .header("Connection", "close") // set a header .then(HttpResponse::gzip); // transform with gzip }
Abstract Methods | |
---|---|
HttpStatus |
status()
Response status.
|
Map<String,String> |
headers()
Response headers.
|
List<Cookie> |
cookies()
Response cookies.
|
HttpEntity |
entity()
Response entity; null if none.
|
Default Methods | |
String |
httpVersion()
The HTTP version of the response.
|
int |
statusCode()
Shorthand for
status().code() . |
String |
header(String name)
Get the value of a header.
|
Async<ByteBuffer> |
bodyBytes(int maxBytes)
Get all the bytes of the entity body.
|
Async<String> |
bodyString(int maxChars)
Get the entity body as a String.
|
Static Methods | |
HttpResponseImpl |
data(int statusCode,
String contentType,
byte[] data)
Create a response with `data` as the body.
|
HttpResponseImpl |
text(int statusCode,
CharSequence... texts)
Create a
"text/plain;charset=UTF-8" response. |
HttpResponseImpl |
html(int statusCode,
CharSequence... htmlContent)
Create a
"text/html;charset=UTF-8" response. |
HttpResponseImpl |
redirect(String uri)
Create a "redirect" response.
|
HttpResponseImpl |
redirect(HttpStatus status,
String uri)
Create a "redirect" response.
|
HttpResponseImpl |
internalError(Throwable error)
Create an internal error response.
|
Async<HttpResponse> |
file(int statusCode,
String filePath)
Create a response serving the file.
|
HttpResponseImpl |
cache(HttpResponse response)
Cache the response in memory, particularly the body.
|
HttpResponseImpl |
gzip(HttpResponse response)
Compress the response with "gzip".
|
HttpResponseImpl |
throttle(long bytesPerSecond,
HttpResponse response)
Throttle the response.
|
default String httpVersion()
It should be two integers separated by a dot, e.g. "1.1".
The default implementation returns "1.1".
HttpStatus status()
"200 OK"
.default int statusCode()
status().code()
.Map<String,String> headers()
The returned Map is case insensitive for lookup. The caller should treat the Map as read-only.
The following headers should not be included in this Map:
"Content-Type"
).
Entity metadata should be expressed on the entity()
.
"Content-Length"
and "Transport-Encoding"
headers.
They are handled automatically by underlying libraries.
"Set-Cookie"
headers. Cookies are represented in cookies()
.
See Headers
for common header names.
See HeaderMap
for a suitable implementation.
See TokenParams
for a certain type of header values.
Note that each header contains a single value. Per spec, multiple headers with the same name is identical in semantics to a single combined header:
Foo: value1 | Foo: value2 | ====> | Foo: value1, value2, value3 Foo: value3 |
default String header(String name)
The default implementation returns headers().get(name)
.
List<Cookie> cookies()
The returned list should be treated as read-only by the caller.
Although response cookies are expressed in "Set-Cookie"
headers on the wire,
they cannot be treated as normal headers (due to a historical oversight).
Therefore headers()
cannot contain "Set-Cookie"
headers;
and, response cookies must be expressed in cookies()
.
HttpResponseImpl.cookies()
,
CookieJar
HttpEntity entity()
A response must have an entity, except in the following cases, where entity() should return null:
If entity()
should return null, but returns non-null, the entity should be ignored.
If the request method is HEAD,
response.entity()
should behave as if the request method is GET,
with the exception of the body - the recipient of the response must not read the entity body.
default Async<ByteBuffer> bodyBytes(int maxBytes)
See HttpEntity.bodyBytes(int)
.
The response body will be closed when this action completes.
If entity
==null, this action succeeds with a `null` ByteBuffer.
default Async<String> bodyString(int maxChars)
See HttpEntity.bodyString(int)
.
The response body will be closed when this action completes.
If entity
==null, this action succeeds with a `null` String.
static HttpResponseImpl data(int statusCode, String contentType, byte[] data)
SimpleHttpEntity
static HttpResponseImpl text(int statusCode, CharSequence... texts)
"text/plain;charset=UTF-8"
response.TextHttpEntity
static HttpResponseImpl html(int statusCode, CharSequence... htmlContent)
"text/html;charset=UTF-8"
response.
See HtmlDoc.toResponse(int)
to create a response for an HtmlDoc.
TextHttpEntity
static HttpResponseImpl redirect(String uri)
The status code is 303
.
See redirect(HttpStatus, String)
if you want a different status code.
The uri can be absolute or relative, for example
"http://example.com"
or "/show?id=123#frag"
.
static HttpResponseImpl redirect(HttpStatus status, String uri)
The status code can be 301/302/303/307/308
.
Choose the status code carefully. See RFC7231 §6.4 for reference.
303
is the proper code.
See also redirect(String)
which uses 303.
301/302
are not clear;
most clients treat them the same as 303
. Try not to use them.
The uri can be absolute or relative, for example
"http://example.com"
or "/show?id=123#frag"
.
static HttpResponseImpl internalError(Throwable error)
The status code is 500
.
The response body contains an "error id" which is a hash value of the `error`. The "error id" is also logged locally for cross reference.
static Async<HttpResponse> file(int statusCode, String filePath)
The Content-Type will be derived from `filePath`,
using FileSuffixToContentType.getGlobalInstance()
.
Be careful if `filePath` is constructed from end user input; normalize it first and make sure the user is allowed to access the file.
If any IO exception occurred (e.g. the file does not exist on disk), the response will be "404 Not Found" instead.
Note that this method returns Async<HttpResponse>
,
not an HttpResponseImpl
. If you need to modify the response,
for example to add a header, try
Async<HttpResponse> fileResp = HttpResponse.file(200, FILE_PATH); fileResp = fileResp.then( r -> new HttpResponseImpl(r).header("foo", "bar") );
static HttpResponseImpl cache(HttpResponse response)
This is a response transforming method, which can often be used in
Async.then(FunctionX)
.
A cached response is often saved, to be served to multiple requests.
Example usage:
static final Async<HttpResponse> respCached = HttpResponse.file(200, "/tmp/big.txt") .then(HttpResponse::gzip) .then(HttpResponse::cache);
See also CachedHttpEntity
.
static HttpResponseImpl gzip(HttpResponse response)
This is a response transforming method, which can often be used in
Async.then(FunctionX)
.
Example usage:
// in http handler return HttpResponse.file(200, "/tmp/big.txt") .then(HttpResponse::gzip);
Response header "Vary: Accept-Encoding"
will be added.
Entity metadata "Etag"
and "Content-Encoding"
will be modified,
see GzipHttpEntity
.
static HttpResponseImpl throttle(long bytesPerSecond, HttpResponse response)
The throttled response will serve the body no faster than the specified `bytesPerSecond`.
Throttling may be useful for simulating slow network on local dev machine.
ThrottledHttpEntity