See: Description
Interface | Description |
---|---|
HttpClient |
An asynchronous HTTP client.
|
HttpClientRequest |
Represents a client-side HTTP request.
|
HttpClientResponse |
Represents a client-side HTTP response.
|
HttpConnection |
Represents an HTTP connection.
|
HttpFrame |
An HTTP/2 frame.
|
HttpServer |
An HTTP and WebSockets server.
|
HttpServerFileUpload |
Represents an file upload from an HTML FORM.
|
HttpServerRequest |
Represents a server-side HTTP request.
|
HttpServerRequestStream | |
HttpServerResponse |
Represents a server-side HTTP response.
|
ServerWebSocket |
Represents a server side WebSocket.
|
ServerWebSocketStream | |
WebSocket |
Represents a client-side WebSocket.
|
WebSocketBase |
Base WebSocket implementation.
|
WebSocketFrame |
A WebSocket frame that represents either text or binary data.
|
WebSocketStream |
A stream for
HttpClient WebSocket connection. |
Class | Description |
---|---|
CaseInsensitiveHeaders |
This multi-map implementation has case insensitive keys, and can be used to hold some HTTP headers
prior to making an HTTP request.
|
GoAway |
A GOAWAY frame.
|
Http2Settings |
HTTP2 settings, the settings is initialized with the default HTTP/2 values.
|
HttpClientOptions |
Options describing how an
HttpClient will make connections. |
HttpHeaders |
Contains often used Header names.
|
HttpServerOptions |
Represents options used by an
HttpServer instance |
Enum | Description |
---|---|
ClientAuth |
Configures the engine to require/request client authentication.
|
HttpMethod |
Represents an HTTP method
|
HttpVersion |
Represents the version of the HTTP protocol.
|
WebsocketVersion |
Represents the WebSocket version
|
Exception | Description |
---|---|
ConnectionPoolTooBusyException |
Represents a failure to add a HttpClientRequest to the wait queue on an ConnectionManager.
|
StreamResetException |
This exception signals a stream reset, it is used only for HTTP/2.
|
examples.HTTPExamples#example1
----
=== Configuring an HTTP server
If you don't want the default, a server can be configured by passing in a HttpServerOptions
instance when creating it:
[source,$lang]
----
examples.HTTPExamples#example2
----
=== Configuring an HTTP/2 server
Vert.x supports HTTP/2 over TLS `h2` and over TCP `h2c`.
- `h2` identifies the HTTP/2 protocol when used over TLS negotiated by https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation[Application-Layer Protocol Negotiation] (ALPN)
- `h2c` identifies the HTTP/2 protocol when using in clear text over TCP, such connections are established either with
an HTTP/1.1 upgraded request or directly
To handle `h2` requests, TLS must be enabled along with HttpServerOptions.setUseAlpn(boolean)
:
[source,$lang]
----
examples.HTTP2Examples#example0
----
ALPN is a TLS extension that negotiates the protocol before the client and the server start to exchange data.
Clients that don't support ALPN will still be able to do a _classic_ SSL handshake.
ALPN will usually agree on the `h2` protocol, although `http/1.1` can be used if the server or the client decides
so.
To handle `h2c` requests, TLS must be disabled, the server will upgrade to HTTP/2 any request HTTP/1.1 that wants to
upgrade to HTTP/2. It will also accept a direct `h2c` connection beginning with the `PRI * HTTP/2.0\r\nSM\r\n` preface.
WARNING: most browsers won't support `h2c`, so for serving web sites you should use `h2` and not `h2c`.
When a server accepts an HTTP/2 connection, it sends to the client its initial settings
.
The settings define how the client can use the connection, the default initial settings for a server are:
- Http2Settings.getMaxConcurrentStreams()
: 100
as recommended by the HTTP/2 RFC
- the default HTTP/2 settings values for the others
=== Logging network server activity
For debugging purposes, network activity can be logged.
[source,$lang]
----
examples.HTTPExamples#exampleServerLogging
----
See the chapter on <HttpServer.listen()
alternatives.
To tell the server to listen at the host and port as specified in the options:
[source,$lang]
----
examples.HTTPExamples#example3
----
Or to specify the host and port in the call to listen, ignoring what is configured in the options:
[source,$lang]
----
examples.HTTPExamples#example4
----
The default host is `0.0.0.0` which means 'listen on all available addresses' and the default port is `80`.
The actual bind is asynchronous so the server might not actually be listening until some time *after* the call to
listen has returned.
If you want to be notified when the server is actually listening you can provide a handler to the `listen` call.
For example:
[source,$lang]
----
examples.HTTPExamples#example5
----
=== Getting notified of incoming requests
To be notified when a request arrives you need to set a HttpServer.requestHandler(io.vertx.core.Handler<io.vertx.core.http.HttpServerRequest>)
:
[source,$lang]
----
examples.HTTPExamples#example6
----
=== Handling requests
When a request arrives, the request handler is called passing in an instance of HttpServerRequest
.
This object represents the server side HTTP request.
The handler is called when the headers of the request have been fully read.
If the request contains a body, that body will arrive at the server some time after the request handler has been called.
The server request object allows you to retrieve the HttpServerRequest.uri()
,
HttpServerRequest.path()
, HttpServerRequest.params()
and
HttpServerRequest.headers()
, amongst other things.
Each server request object is associated with one server response object. You use
HttpServerRequest.response()
to get a reference to the HttpServerResponse
object.
Here's a simple example of a server handling a request and replying with "hello world" to it.
[source,$lang]
----
examples.HTTPExamples#example7_1
----
==== Request version
The version of HTTP specified in the request can be retrieved with HttpServerRequest.version()
==== Request method
Use HttpServerRequest.method()
to retrieve the HTTP method of the request.
(i.e. whether it's GET, POST, PUT, DELETE, HEAD, OPTIONS, etc).
==== Request URI
Use HttpServerRequest.uri()
to retrieve the URI of the request.
Note that this is the actual URI as passed in the HTTP request, and it's almost always a relative URI.
The URI is as defined in http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html[Section 5.1.2 of the HTTP specification - Request-URI]
==== Request path
Use HttpServerRequest.path()
to return the path part of the URI
For example, if the request URI was:
a/b/c/page.html?param1=abc¶m2=xyz
Then the path would be
/a/b/c/page.html
==== Request query
Use HttpServerRequest.query()
to return the query part of the URI
For example, if the request URI was:
a/b/c/page.html?param1=abc¶m2=xyz
Then the query would be
param1=abc¶m2=xyz
==== Request headers
Use HttpServerRequest.headers()
to return the headers of the HTTP request.
This returns an instance of MultiMap
- which is like a normal Map or Hash but allows multiple
values for the same key - this is because HTTP allows multiple header values with the same key.
It also has case-insensitive keys, that means you can do the following:
[source,$lang]
----
examples.HTTPExamples#example8
----
==== Request host
Use HttpServerRequest.host()
to return the host of the HTTP request.
For HTTP/1.x requests the `host` header is returned, for HTTP/1 requests the `:authority` pseudo header is returned.
==== Request parameters
Use HttpServerRequest.params()
to return the parameters of the HTTP request.
Just like HttpServerRequest.headers()
this returns an instance of MultiMap
as there can be more than one parameter with the same name.
Request parameters are sent on the request URI, after the path. For example if the URI was:
/page.html?param1=abc¶m2=xyz
Then the parameters would contain the following:
----
param1: 'abc'
param2: 'xyz
----
Note that these request parameters are retrieved from the URL of the request. If you have form attributes that
have been sent as part of the submission of an HTML form submitted in the body of a `multi-part/form-data` request
then they will not appear in the params here.
==== Remote address
The address of the sender of the request can be retrieved with HttpServerRequest.remoteAddress()
.
==== Absolute URI
The URI passed in an HTTP request is usually relative. If you wish to retrieve the absolute URI corresponding
to the request, you can get it with HttpServerRequest.absoluteURI()
==== End handler
The HttpServerRequest.endHandler(io.vertx.core.Handler<java.lang.Void>)
of the request is invoked when the entire request,
including any body has been fully read.
==== Reading Data from the Request Body
Often an HTTP request contains a body that we want to read. As previously mentioned the request handler is called
when just the headers of the request have arrived so the request object does not have a body at that point.
This is because the body may be very large (e.g. a file upload) and we don't generally want to buffer the entire
body in memory before handing it to you, as that could cause the server to exhaust available memory.
To receive the body, you can use the HttpServerRequest.handler(io.vertx.core.Handler<io.vertx.core.buffer.Buffer>)
on the request,
this will get called every time a chunk of the request body arrives. Here's an example:
[source,$lang]
----
examples.HTTPExamples#example9
----
The object passed into the handler is a Buffer
, and the handler can be called
multiple times as data arrives from the network, depending on the size of the body.
In some cases (e.g. if the body is small) you will want to aggregate the entire body in memory, so you could do
the aggregation yourself as follows:
[source,$lang]
----
examples.HTTPExamples#example10
----
This is such a common case, that Vert.x provides a HttpServerRequest.bodyHandler(io.vertx.core.Handler<io.vertx.core.buffer.Buffer>)
to do this
for you. The body handler is called once when all the body has been received:
[source,$lang]
----
examples.HTTPExamples#example11
----
==== Pumping requests
The request object is a ReadStream
so you can pump the request body to any
WriteStream
instance.
See the chapter on <HttpServerRequest.setExpectMultipart(boolean)
with true, and then you should retrieve the actual attributes using HttpServerRequest.formAttributes()
once the entire body has been read:
[source,$lang]
----
examples.HTTPExamples#example12
----
==== Handling form file uploads
Vert.x can also handle file uploads which are encoded in a multi-part request body.
To receive file uploads you tell Vert.x to expect a multi-part form and set an
HttpServerRequest.uploadHandler(io.vertx.core.Handler<io.vertx.core.http.HttpServerFileUpload>)
on the request.
This handler will be called once for every
upload that arrives on the server.
The object passed into the handler is a HttpServerFileUpload
instance.
[source,$lang]
----
examples.HTTPExamples#example13
----
File uploads can be large we don't provide the entire upload in a single buffer as that might result in memory
exhaustion, instead, the upload data is received in chunks:
[source,$lang]
----
examples.HTTPExamples#example14
----
The upload object is a ReadStream
so you can pump the request body to any
WriteStream
instance. See the chapter on <HttpServerFileUpload.streamToFileSystem(java.lang.String)
:
[source,$lang]
----
examples.HTTPExamples#example15
----
WARNING: Make sure you check the filename in a production system to avoid malicious clients uploading files
to arbitrary places on your filesystem. See <HttpServerRequest.customFrameHandler(io.vertx.core.Handler<io.vertx.core.http.HttpFrame>)
on the request,
this will get called every time a custom frame arrives. Here's an example:
[source,$lang]
----
examples.HTTP2Examples#example1
----
HTTP/2 frames are not subject to flow control - the frame handler will be called immediatly when a
custom frame is received whether the request is paused or is not
==== Non standard HTTP methods
The HttpMethod.OTHER
HTTP method is used for non standard methods, in this case
HttpServerRequest.rawMethod()
returns the HTTP method as sent by the client.
=== Sending back responses
The server response object is an instance of HttpServerResponse
and is obtained from the
request with HttpServerRequest.response()
.
You use the response object to write a response back to the HTTP client.
==== Setting status code and message
The default HTTP status code for a response is `200`, representing `OK`.
Use HttpServerResponse.setStatusCode(int)
to set a different code.
You can also specify a custom status message with HttpServerResponse.setStatusMessage(java.lang.String)
.
If you don't specify a status message, the default one corresponding to the status code will be used.
NOTE: for HTTP/2 the status won't be present in the response since the protocol won't transmit the message
to the client
==== Writing HTTP responses
To write data to an HTTP response, you use one the HttpServerResponse.write(io.vertx.core.buffer.Buffer)
operations.
These can be invoked multiple times before the response is ended. They can be invoked in a few ways:
With a single buffer:
[source,$lang]
----
examples.HTTPExamples#example16
----
With a string. In this case the string will encoded using UTF-8 and the result written to the wire.
[source,$lang]
----
examples.HTTPExamples#example17
----
With a string and an encoding. In this case the string will encoded using the specified encoding and the
result written to the wire.
[source,$lang]
----
examples.HTTPExamples#example18
----
Writing to a response is asynchronous and always returns immediately after the write has been queued.
If you are just writing a single string or buffer to the HTTP response you can write it and end the response in a
single call to the HttpServerResponse.end(String)
The first call to write results in the response header being being written to the response. Consequently, if you are
not using HTTP chunking then you must set the `Content-Length` header before writing to the response, since it will
be too late otherwise. If you are using HTTP chunking you do not have to worry.
==== Ending HTTP responses
Once you have finished with the HTTP response you should HttpServerResponse.end(java.lang.String)
it.
This can be done in several ways:
With no arguments, the response is simply ended.
[source,$lang]
----
examples.HTTPExamples#example19
----
It can also be called with a string or buffer in the same way `write` is called. In this case it's just the same as
calling write with a string or buffer followed by calling end with no arguments. For example:
[source,$lang]
----
examples.HTTPExamples#example20
----
==== Closing the underlying connection
You can close the underlying TCP connection with HttpServerResponse.close()
.
Non keep-alive connections will be automatically closed by Vert.x when the response is ended.
Keep-alive connections are not automatically closed by Vert.x by default. If you want keep-alive connections to be
closed after an idle time, then you configure HttpServerOptions.setIdleTimeout(int)
.
HTTP/2 connections send a GOAWAY frame before closing the response.
==== Setting response headers
HTTP response headers can be added to the response by adding them directly to the
HttpServerResponse.headers()
:
[source,$lang]
----
examples.HTTPExamples#example21
----
Or you can use HttpServerResponse.putHeader(java.lang.String, java.lang.String)
[source,$lang]
----
examples.HTTPExamples#example22
----
Headers must all be added before any parts of the response body are written.
==== Chunked HTTP responses and trailers
Vert.x supports http://en.wikipedia.org/wiki/Chunked_transfer_encoding[HTTP Chunked Transfer Encoding].
This allows the HTTP response body to be written in chunks, and is normally used when a large response body is
being streamed to a client and the total size is not known in advance.
You put the HTTP response into chunked mode as follows:
[source,$lang]
----
examples.HTTPExamples#example23
----
Default is non-chunked. When in chunked mode, each call to one of the HttpServerResponse.write(io.vertx.core.buffer.Buffer)
methods will result in a new HTTP chunk being written out.
When in chunked mode you can also write HTTP response trailers to the response. These are actually written in
the final chunk of the response.
NOTE: chunked response has no effect for an HTTP/2 stream
To add trailers to the response, add them directly to the HttpServerResponse.trailers()
.
[source,$lang]
----
examples.HTTPExamples#example24
----
Or use HttpServerResponse.putTrailer(java.lang.String, java.lang.String)
.
[source,$lang]
----
examples.HTTPExamples#example25
----
==== Serving files directly from disk or the classpath
If you were writing a web server, one way to serve a file from disk would be to open it as an AsyncFile
and pump it to the HTTP response.
Or you could load it it one go using FileSystem.readFile(java.lang.String, io.vertx.core.Handler<io.vertx.core.AsyncResult<io.vertx.core.buffer.Buffer>>)
and write it straight to the response.
Alternatively, Vert.x provides a method which allows you to serve a file from disk or the filesystem to an HTTP response
in one operation.
Where supported by the underlying operating system this may result in the OS directly transferring bytes from the
file to the socket without being copied through user-space at all.
This is done by using HttpServerResponse.sendFile(java.lang.String)
, and is usually more efficient for large
files, but may be slower for small files.
Here's a very simple web server that serves files from the file system using sendFile:
[source,$lang]
----
examples.HTTPExamples#example26
----
Sending a file is asynchronous and may not complete until some time after the call has returned. If you want to
be notified when the file has been writen you can use HttpServerResponse.sendFile(String, io.vertx.core.Handler)
Please see the chapter about <examples.HTTPExamples#example26b
----
You are not required to supply the length if you want to send a file starting from an offset until the end, in this
case you can just do:
[source,$lang]
----
examples.HTTPExamples#example26c
----
==== Pumping responses
The server response is a WriteStream
instance so you can pump to it from any
ReadStream
, e.g. AsyncFile
, NetSocket
,
WebSocket
or HttpServerRequest
.
Here's an example which echoes the request body back in the response for any PUT methods.
It uses a pump for the body, so it will work even if the HTTP request body is much larger than can fit in memory
at any one time:
[source,$lang]
----
examples.HTTPExamples#example27
----
==== Writing HTTP/2 frames
HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind
of frames to be sent and received.
To send such frames, you can use the HttpServerResponse.writeCustomFrame(int, int, io.vertx.core.buffer.Buffer)
on the response.
Here's an example:
[source,$lang]
----
examples.HTTP2Examples#example2
----
These frames are sent immediately and are not subject to flow control - when such frame is sent there it may be done
before other DATA frames.
==== Stream reset
HTTP/1.x does not allow a clean reset of a request or a response stream, for example when a client uploads
a resource already present on the server, the server needs to accept the entire response.
HTTP/2 supports stream reset at any time during the request/response:
[source,$lang]
----
examples.HTTP2Examples#example3
----
By default the `NO_ERROR` (0) error code is sent, another code can sent instead:
[source,$lang]
----
examples.HTTP2Examples#example4
----
The HTTP/2 specification defines the list of http://httpwg.org/specs/rfc7540.html#ErrorCodes[error codes] one can use.
The request handler are notified of stream reset events with the request handler
and
response handler
:
[source,$lang]
----
examples.HTTP2Examples#example5
----
==== Server push
Server push is a new feature of HTTP/2 that enables sending multiple responses in parallel for a single client request.
When a server process a request, it can push a request/response to the client:
[source,$lang]
----
examples.HTTP2Examples#example6
----
When the server is ready to push the response, the push response handler is called and the handler can send the response.
The push response handler may receive a failure, for instance the client may cancel the push because it already has `main.js` in its
cache and does not want it anymore.
The HttpServerResponse.push(io.vertx.core.http.HttpMethod, java.lang.String, java.lang.String, io.vertx.core.Handler<io.vertx.core.AsyncResult<io.vertx.core.http.HttpServerResponse>>)
method must be called before the initiating response ends, however
the pushed response can be written after.
=== HTTP Compression
Vert.x comes with support for HTTP Compression out of the box.
This means you are able to automatically compress the body of the responses before they are sent back to the client.
If the client does not support HTTP compression the responses are sent back without compressing the body.
This allows to handle Client that support HTTP Compression and those that not support it at the same time.
To enable compression use can configure it with HttpServerOptions.setCompressionSupported(boolean)
.
By default compression is not enabled.
When HTTP compression is enabled the server will check if the client includes an `Accept-Encoding` header which
includes the supported compressions. Commonly used are deflate and gzip. Both are supported by Vert.x.
If such a header is found the server will automatically compress the body of the response with one of the supported
compressions and send it back to the client.
Be aware that compression may be able to reduce network traffic but is more CPU-intensive.
=== Creating an HTTP client
You create an HttpClient
instance with default options as follows:
[source,$lang]
----
examples.HTTPExamples#example28
----
If you want to configure options for the client, you create it as follows:
[source,$lang]
----
examples.HTTPExamples#example29
----
Vert.x supports HTTP/2 over TLS `h2` and over TCP `h2c`.
By default the http client performs HTTP/1.1 requests, to perform HTTP/2 requests the HttpClientOptions.setProtocolVersion(io.vertx.core.http.HttpVersion)
must be set to HttpVersion.HTTP_2
.
For `h2` requests, TLS must be enabled with _Application-Layer Protocol Negotiation_:
[source,$lang]
----
examples.HTTP2Examples#example7
----
For `h2c` requests, TLS must be disabled, the client will do an HTTP/1.1 requests and try an upgrade to HTTP/2:
[source,$lang]
----
examples.HTTP2Examples#example8
----
`h2c` connections can also be established directly, i.e connection started with a prior knowledge, when
HttpClientOptions.setHttp2ClearTextUpgrade(boolean)
options is set to false: after the
connection is established, the client will send the HTTP/2 connection preface and expect to receive
the same preface from the server.
The http server may not support HTTP/2, the actual version can be checked
with HttpClientResponse.version()
when the response arrives.
When a clients connects to an HTTP/2 server, it sends to the server its initial settings
.
The settings define how the server can use the connection, the default initial settings for a client are the default
values defined by the HTTP/2 RFC.
=== Logging network client activity
For debugging purposes, network activity can be logged.
[source,$lang]
----
examples.HTTPExamples#exampleClientLogging
----
See the chapter on <examples.HTTPExamples#example30
----
Alternatively if you find yourself making lots of requests to different host/ports with the same client you can
simply specify the host/port when doing the request.
[source,$lang]
----
examples.HTTPExamples#example31
----
Both methods of specifying host/port are supported for all the different ways of making requests with the client.
==== Simple requests with no request body
Often, you'll want to make HTTP requests with no request body. This is usually the case with HTTP GET, OPTIONS and
HEAD requests.
The simplest way to do this with the Vert.x http client is using the methods prefixed with `Now`. For example
HttpClient.getNow(int, java.lang.String, java.lang.String, io.vertx.core.Handler<io.vertx.core.http.HttpClientResponse>)
.
These methods create the http request and send it in a single method call and allow you to provide a handler that will be
called with the http response when it comes back.
[source,$lang]
----
examples.HTTPExamples#example32
----
==== Writing general requests
At other times you don't know the request method you want to send until run-time. For that use case we provide
general purpose request methods such as HttpClient.request(io.vertx.core.http.HttpMethod, int, java.lang.String, java.lang.String)
which allow you to specify
the HTTP method at run-time:
[source,$lang]
----
examples.HTTPExamples#example33
----
==== Writing request bodies
Sometimes you'll want to write requests which have a body, or perhaps you want to write headers to a request
before sending it.
To do this you can call one of the specific request methods such as HttpClient.post(int, java.lang.String, java.lang.String)
or
one of the general purpose request methods such as HttpClient.request(io.vertx.core.http.HttpMethod, int, java.lang.String, java.lang.String)
.
These methods don't send the request immediately, but instead return an instance of HttpClientRequest
which can be used to write to the request body or write headers.
Here are some examples of writing a POST request with a body:
m
[source,$lang]
----
examples.HTTPExamples#example34
----
Methods exist to write strings in UTF-8 encoding and in any specific encoding and to write buffers:
[source,$lang]
----
examples.HTTPExamples#example35
----
If you are just writing a single string or buffer to the HTTP request you can write it and end the request in a
single call to the `end` function.
[source,$lang]
----
examples.HTTPExamples#example36
----
When you're writing to a request, the first call to `write` will result in the request headers being written
out to the wire.
The actual write is asynchronous and might not occur until some time after the call has returned.
Non-chunked HTTP requests with a request body require a `Content-Length` header to be provided.
Consequently, if you are not using chunked HTTP then you must set the `Content-Length` header before writing
to the request, as it will be too late otherwise.
If you are calling one of the `end` methods that take a string or buffer then Vert.x will automatically calculate
and set the `Content-Length` header before writing the request body.
If you are using HTTP chunking a a `Content-Length` header is not required, so you do not have to calculate the size
up-front.
==== Writing request headers
You can write headers to a request using the HttpClientRequest.headers()
multi-map as follows:
[source,$lang]
----
examples.HTTPExamples#example37
----
The headers are an instance of MultiMap
which provides operations for adding, setting and removing
entries. Http headers allow more than one value for a specific key.
You can also write headers using HttpClientRequest.putHeader(java.lang.String, java.lang.String)
[source,$lang]
----
examples.HTTPExamples#example38
----
If you wish to write headers to the request you must do so before any part of the request body is written.
==== Non standard HTTP methods
The HttpMethod.OTHER
HTTP method is used for non standard methods, when this method
is used, HttpClientRequest.setRawMethod(java.lang.String)
must be used to
set the raw method to send to the server.
==== Ending HTTP requests
Once you have finished with the HTTP request you must end it with one of the HttpClientRequest.end(java.lang.String)
operations.
Ending a request causes any headers to be written, if they have not already been written and the request to be marked
as complete.
Requests can be ended in several ways. With no arguments the request is simply ended:
[source,$lang]
----
examples.HTTPExamples#example39
----
Or a string or buffer can be provided in the call to `end`. This is like calling `write` with the string or buffer
before calling `end` with no arguments
[source,$lang]
----
examples.HTTPExamples#example40
----
==== Chunked HTTP requests
Vert.x supports http://en.wikipedia.org/wiki/Chunked_transfer_encoding[HTTP Chunked Transfer Encoding] for requests.
This allows the HTTP request body to be written in chunks, and is normally used when a large request body is being streamed
to the server, whose size is not known in advance.
You put the HTTP request into chunked mode using HttpClientRequest.setChunked(boolean)
.
In chunked mode each call to write will cause a new chunk to be written to the wire. In chunked mode there is
no need to set the `Content-Length` of the request up-front.
[source,$lang]
----
examples.HTTPExamples#example41
----
==== Request timeouts
You can set a timeout for a specific http request using HttpClientRequest.setTimeout(long)
.
If the request does not return any data within the timeout period an exception will be passed to the exception handler
(if provided) and the request will be closed.
==== Handling exceptions
You can handle exceptions corresponding to a request by setting an exception handler on the
HttpClientRequest
instance:
[source,$lang]
----
examples.HTTPExamples#example42
----
This does not handle non _2xx_ response that need to be handled in the
HttpClientResponse
code:
[source, $lang]
----
examples.HTTPExamples#statusCodeHandling
----
IMPORTANT: `XXXNow` methods cannot receive an exception handler.
==== Specifying a handler on the client request
Instead of providing a response handler in the call to create the client request object, alternatively, you can
not provide a handler when the request is created and set it later on the request object itself, using
HttpClientRequest.handler(io.vertx.core.Handler)
, for example:
[source,$lang]
----
examples.HTTPExamples#example43
----
==== Using the request as a stream
The HttpClientRequest
instance is also a WriteStream
which means
you can pump to it from any ReadStream
instance.
For, example, you could pump a file on disk to a http request body as follows:
[source,$lang]
----
examples.HTTPExamples#example44
----
==== Writing HTTP/2 frames
HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind
of frames to be sent and received.
To send such frames, you can use the HttpClientRequest.write(io.vertx.core.buffer.Buffer)
on the request. Here's an example:
[source,$lang]
----
examples.HTTP2Examples#example9
----
==== Stream reset
HTTP/1.x does not allow a clean reset of a request or a response stream, for example when a client uploads a resource already
present on the server, the server needs to accept the entire response.
HTTP/2 supports stream reset at any time during the request/response:
[source,$lang]
----
examples.HTTP2Examples#example10
----
By default the NO_ERROR (0) error code is sent, another code can sent instead:
[source,$lang]
----
examples.HTTP2Examples#example11
----
The HTTP/2 specification defines the list of http://httpwg.org/specs/rfc7540.html#ErrorCodes[error codes] one can use.
The request handler are notified of stream reset events with the request handler
and
response handler
:
[source,$lang]
----
examples.HTTP2Examples#example12
----
=== Handling http responses
You receive an instance of HttpClientResponse
into the handler that you specify in of
the request methods or by setting a handler directly on the HttpClientRequest
object.
You can query the status code and the status message of the response with HttpClientResponse.statusCode()
and HttpClientResponse.statusMessage()
.
[source,$lang]
----
examples.HTTPExamples#example45
----
==== Using the response as a stream
The HttpClientResponse
instance is also a ReadStream
which means
you can pump it to any WriteStream
instance.
==== Response headers and trailers
Http responses can contain headers. Use HttpClientResponse.headers()
to get the headers.
The object returned is a MultiMap
as HTTP headers can contain multiple values for single keys.
[source,$lang]
----
examples.HTTPExamples#example46
----
Chunked HTTP responses can also contain trailers - these are sent in the last chunk of the response body.
You use HttpClientResponse.trailers()
to get the trailers. Trailers are also a MultiMap
.
==== Reading the request body
The response handler is called when the headers of the response have been read from the wire.
If the response has a body this might arrive in several pieces some time after the headers have been read. We
don't wait for all the body to arrive before calling the response handler as the response could be very large and we
might be waiting a long time, or run out of memory for large responses.
As parts of the response body arrive, the HttpClientResponse.handler(io.vertx.core.Handler<io.vertx.core.buffer.Buffer>)
is called with
a Buffer
representing the piece of the body:
[source,$lang]
----
examples.HTTPExamples#example47
----
If you know the response body is not very large and want to aggregate it all in memory before handling it, you can
either aggregate it yourself:
[source,$lang]
----
examples.HTTPExamples#example48
----
Or you can use the convenience HttpClientResponse.bodyHandler(io.vertx.core.Handler)
which
is called with the entire body when the response has been fully read:
[source,$lang]
----
examples.HTTPExamples#example49
----
==== Response end handler
The response HttpClientResponse.endHandler(io.vertx.core.Handler<java.lang.Void>)
is called when the entire response body has been read
or immediately after the headers have been read and the response handler has been called if there is no body.
==== Reading cookies from the response
You can retrieve the list of cookies from a response using HttpClientResponse.cookies()
.
Alternatively you can just parse the `Set-Cookie` headers yourself in the response.
==== 100-Continue handling
According to the http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html[HTTP 1.1 specification] a client can set a
header `Expect: 100-Continue` and send the request header before sending the rest of the request body.
The server can then respond with an interim response status `Status: 100 (Continue)` to signify to the client that
it is ok to send the rest of the body.
The idea here is it allows the server to authorise and accept/reject the request before large amounts of data are sent.
Sending large amounts of data if the request might not be accepted is a waste of bandwidth and ties up the server
in reading data that it will just discard.
Vert.x allows you to set a HttpClientRequest.continueHandler(io.vertx.core.Handler)
on the
client request object
This will be called if the server sends back a `Status: 100 (Continue)` response to signify that it is ok to send
the rest of the request.
This is used in conjunction with HttpClientRequest.sendHead()
to send the head of the request.
Here's an example:
[source,$lang]
----
examples.HTTPExamples#example50
----
On the server side a Vert.x http server can be configured to automatically send back 100 Continue interim responses
when it receives an `Expect: 100-Continue` header.
This is done by setting the option HttpServerOptions.setHandle100ContinueAutomatically(boolean)
.
If you'd prefer to decide whether to send back continue responses manually, then this property should be set to
`false` (the default), then you can inspect the headers and call HttpServerResponse.writeContinue()
to have the client continue sending the body:
[source,$lang]
----
examples.HTTPExamples#example50_1
----
You can also reject the request by sending back a failure status code directly: in this case the body
should either be ignored or the connection should be closed (100-Continue is a performance hint and
cannot be a logical protocol constraint):
[source,$lang]
----
examples.HTTPExamples#example50_2
----
==== Client push
Server push is a new feature of HTTP/2 that enables sending multiple responses in parallel for a single client request.
A push handler can be set on a request to receive the request/response pushed by the server:
[source,$lang]
----
examples.HTTP2Examples#example13
----
If the client does not want to receive a pushed request, it can reset the stream:
[source,$lang]
----
examples.HTTP2Examples#example14
----
When no handler is set, any stream pushed will be automatically cancelled by the client with
a stream reset (`8` error code).
==== Receiving custom HTTP/2 frames
HTTP/2 is a framed protocol with various frames for the HTTP request/response model. The protocol allows other kind of
frames to be sent and received.
To receive custom frames, you can use the customFrameHandler on the request, this will get called every time a custom
frame arrives. Here's an example:
[source,$lang]
----
examples.HTTP2Examples#example15
----
=== Enabling compression on the client
The http client comes with support for HTTP Compression out of the box.
This means the client can let the remote http server know that it supports compression, and will be able to handle
compressed response bodies.
An http server is free to either compress with one of the supported compression algorithms or to send the body back
without compressing it at all. So this is only a hint for the Http server which it may ignore at will.
To tell the http server which compression is supported by the client it will include an `Accept-Encoding` header with
the supported compression algorithm as value. Multiple compression algorithms are supported. In case of Vert.x this
will result in the following header added:
Accept-Encoding: gzip, deflate
The server will choose then from one of these. You can detect if a server ompressed the body by checking for the
`Content-Encoding` header in the response sent back from it.
If the body of the response was compressed via gzip it will include for example the following header:
Content-Encoding: gzip
To enable compression set HttpClientOptions.setTryUseCompression(boolean)
on the options
used when creating the client.
By default compression is disabled.
=== HTTP/1.x pooling and keep alive
Http keep alive allows http connections to be used for more than one request. This can be a more efficient use of
connections when you're making multiple requests to the same server.
For HTTP/1.x versions, the http client supports pooling of connections, allowing you to reuse connections between requests.
For pooling to work, keep alive must be true using HttpClientOptions.setKeepAlive(boolean)
on the options used when configuring the client. The default value is true.
When keep alive is enabled. Vert.x will add a `Connection: Keep-Alive` header to each HTTP/1.0 request sent.
When keep alive is disabled. Vert.x will add a `Connection: Close` header to each HTTP/1.1 request sent to signal
that the connection will be closed after completion of the response.
The maximum number of connections to pool *for each server* is configured using HttpClientOptions.setMaxPoolSize(int)
When making a request with pooling enabled, Vert.x will create a new connection if there are less than the maximum number of
connections already created for that server, otherwise it will add the request to a queue.
Keep alive connections will not be closed by the client automatically. To close them you can close the client instance.
Alternatively you can set idle timeout using HttpClientOptions.setIdleTimeout(int)
- any
connections not used within this timeout will be closed. Please note the idle timeout value is in seconds not milliseconds.
=== HTTP/1.1 pipe-lining
The client also supports pipe-lining of requests on a connection.
Pipe-lining means another request is sent on the same connection before the response from the preceding one has
returned. Pipe-lining is not appropriate for all requests.
To enable pipe-lining, it must be enabled using HttpClientOptions.setPipelining(boolean)
.
By default pipe-lining is disabled.
When pipe-lining is enabled requests will be written to connections without waiting for previous responses to return.
The number of pipe-lined requests over a single connection is limited by HttpClientOptions.setPipeliningLimit(int)
.
This option defines the maximum number of http requests sent to the server awaiting for a response. This limit ensures the
fairness of the distribution of the client requests over the connections to the same server.
=== HTTP/2 multiplexing
HTTP/2 advocates to use a single connection to a server, by default the http client uses a single
connection for each server, all the streams to the same server are multiplexed over the same connection.
When the clients needs to use more than a single connection and use pooling, the HttpClientOptions.setHttp2MaxPoolSize(int)
shall be used.
When it is desirable to limit the number of multiplexed streams per connection and use a connection
pool instead of a single connection, HttpClientOptions.setHttp2MultiplexingLimit(int)
can be used.
[source,$lang]
----
examples.HTTP2Examples#useMaxStreams
----
The multiplexing limit for a connection is a setting set on the client that limits the number of streams
of a single connection. The effective value can be even lower if the server sets a lower limit
with the SETTINGS_MAX_CONCURRENT_STREAMS
setting.
HTTP/2 connections will not be closed by the client automatically. To close them you can call HttpConnection.close()
or close the client instance.
Alternatively you can set idle timeout using HttpClientOptions.setIdleTimeout(int)
- any
connections not used within this timeout will be closed. Please note the idle timeout value is in seconds not milliseconds.
=== HTTP connections
The HttpConnection
offers the API for dealing with HTTP connection events, lifecycle
and settings.
HTTP/2 implements fully the HttpConnection
API.
HTTP/1.x implements partially the HttpConnection
API: only the close operation,
the close handler and exception handler are implemented. This protocol does not provide semantics for
the other operations.
==== Server connections
The HttpServerRequest.connection()
method returns the request connection on the server:
[source,$lang]
----
examples.HTTP2Examples#example16
----
A connection handler can be set on the server to be notified of any incoming connection:
[source,$lang]
----
examples.HTTP2Examples#example17
----
==== Client connections
The HttpClientRequest.connection()
method returns the request connection on the client:
[source,$lang]
----
examples.HTTP2Examples#example18
----
A connection handler can be set on the request to be notified when the connection happens:
[source,$lang]
----
examples.HTTP2Examples#example19
----
==== Connection settings
The configuration of an HTTP/2 is configured by the Http2Settings
data object.
Each endpoint must respect the settings sent by the other side of the connection.
When a connection is established, the client and the server exchange initial settings. Initial settings
are configured by HttpClientOptions.setInitialSettings(io.vertx.core.http.Http2Settings)
on the client and
HttpServerOptions.setInitialSettings(io.vertx.core.http.Http2Settings)
on the server.
The settings can be changed at any time after the connection is established:
[source,$lang]
----
examples.HTTP2Examples#example20
----
As the remote side should acknowledge on reception of the settings update, it's possible to give a callback
to be notified of the acknowledgment:
[source,$lang]
----
examples.HTTP2Examples#example21
----
Conversely the HttpConnection.remoteSettingsHandler(io.vertx.core.Handler)
is notified
when the new remote settings are received:
[source,$lang]
----
examples.HTTP2Examples#example22
----
NOTE: this only applies to the HTTP/2 protocol
==== Connection ping
HTTP/2 connection ping is useful for determining the connection round-trip time or check the connection
validity: HttpConnection.ping(io.vertx.core.buffer.Buffer, io.vertx.core.Handler<io.vertx.core.AsyncResult<io.vertx.core.buffer.Buffer>>)
sends a PING frame to the remote
endpoint:
[source,$lang]
----
examples.HTTP2Examples#example23
----
Vert.x will send automatically an acknowledgement when a PING frame is received,
an handler can be set to be notified for each ping received:
[source,$lang]
----
examples.HTTP2Examples#example24
----
The handler is just notified, the acknowledgement is sent whatsoever. Such feature is aimed for
implementing protocols on top of HTTP/2.
NOTE: this only applies to the HTTP/2 protocol
==== Connection shutdown and go away
Calling HttpConnection.shutdown()
will send a GOAWAY frame to the
remote side of the connection, asking it to stop creating streams: a client will stop doing new requests
and a server will stop pushing responses. After the GOAWAY frame is sent, the connection
waits some time (30 seconds by default) until all current streams closed and close the connection:
[source,$lang]
----
examples.HTTP2Examples#example25
----
The HttpConnection.shutdownHandler(io.vertx.core.Handler<java.lang.Void>)
notifies when all streams have been closed, the
connection is not yet closed.
It's possible to just send a GOAWAY frame, the main difference with a shutdown is that
it will just tell the remote side of the connection to stop creating new streams without scheduling a connection
close:
[source,$lang]
----
examples.HTTP2Examples#example26
----
Conversely, it is also possible to be notified when GOAWAY are received:
[source,$lang]
----
examples.HTTP2Examples#example27
----
The HttpConnection.shutdownHandler(io.vertx.core.Handler<java.lang.Void>)
will be called when all current streams
have been closed and the connection can be closed:
[source,$lang]
----
examples.HTTP2Examples#example28
----
This applies also when a GOAWAY is received.
NOTE: this only applies to the HTTP/2 protocol
==== Connection close
Connection HttpConnection.close()
closes the connection:
- it closes the socket for HTTP/1.x
- a shutdown with no delay for HTTP/2, the GOAWAY frame will still be sent before the connection is closed. *
The HttpConnection.closeHandler(io.vertx.core.Handler<java.lang.Void>)
notifies when a connection is closed.
=== HttpClient usage
The HttpClient can be used in a Verticle or embedded.
When used in a Verticle, the Verticle *should use its own client instance*.
More generally a client should not be shared between different Vert.x contexts as it can lead to unexpected behavior.
For example a keep-alive connection will call the client handlers on the context of the request that opened the connection, subsequent requests will use
the same context.
When this happen Vert.x detects it and log a warn:
----
Reusing a connection with a different context: an HttpClient is probably shared between different Verticles
----
The HttpClient can be embedded in a non Vert.x thread like a unit test or a plain java `main`: the client handlers
will be called by different Vert.x threads and contexts, such contexts are created as needed. For production this
usage is not recommended.
=== Server sharing
When several HTTP servers listen on the same port, vert.x orchestrates the request handling using a
round-robin strategy.
Let's take a verticle creating a HTTP server such as:
.io.vertx.examples.http.sharing.HttpServerVerticle
[source,$lang]
----
examples.HTTPExamples#serversharing(io.vertx.core.Vertx)
----
This service is listening on the port 8080. So, when this verticle is instantiated multiple times as with:
`vertx run io.vertx.examples.http.sharing.HttpServerVerticle -instances 2`, what's happening ? If both
verticles would bind to the same port, you would receive a socket exception. Fortunately, vert.x is handling
this case for you. When you deploy another server on the same host and port as an existing server it doesn't
actually try and create a new server listening on the same host/port. It binds only once to the socket. When
receiving a request it calls the server handlers following a round robin strategy.
Let's now imagine a client such as:
[source,$lang]
----
examples.HTTPExamples#serversharingclient(io.vertx.core.Vertx)
----
Vert.x delegates the requests to one of the server sequentially:
[source]
----
Hello from i.v.e.h.s.HttpServerVerticle@1
Hello from i.v.e.h.s.HttpServerVerticle@2
Hello from i.v.e.h.s.HttpServerVerticle@1
Hello from i.v.e.h.s.HttpServerVerticle@2
...
----
Consequently the servers can scale over available cores while each Vert.x verticle instance remains strictly
single threaded, and you don't have to do any special tricks like writing load-balancers in order to scale your
server on your multi-core machine.
=== Using HTTPS with Vert.x
Vert.x http servers and clients can be configured to use HTTPS in exactly the same way as net servers.
Please see <HttpServer.websocketHandler(io.vertx.core.Handler)
on the server instance.
When a WebSocket connection is made to the server, the handler will be called, passing in an instance of
ServerWebSocket
.
[source,$lang]
----
examples.HTTPExamples#example51
----
You can choose to reject the WebSocket by calling ServerWebSocket.reject()
.
[source,$lang]
----
examples.HTTPExamples#example52
----
===== Upgrading to WebSocket
The second way of handling WebSockets is to handle the HTTP Upgrade request that was sent from the client, and
call HttpServerRequest.upgrade()
on the server request.
[source,$lang]
----
examples.HTTPExamples#example53
----
===== The server WebSocket
The ServerWebSocket
instance enables you to retrieve the headers
,
path
, query
and
URI
of the HTTP request of the WebSocket handshake.
==== WebSockets on the client
The Vert.x HttpClient
supports WebSockets.
You can connect a WebSocket to a server using one of the HttpClient.websocket(int, java.lang.String, java.lang.String, io.vertx.core.Handler<io.vertx.core.http.WebSocket>)
operations and
providing a handler.
The handler will be called with an instance of WebSocket
when the connection has been made:
[source,$lang]
----
examples.HTTPExamples#example54
----
==== Writing messages to WebSockets
If you wish to write a single binary WebSocket message to the WebSocket you can do this with
WebSocket.writeBinaryMessage(io.vertx.core.buffer.Buffer)
:
[source,$lang]
----
examples.HTTPExamples#example55
----
If the WebSocket message is larger than the maximum websocket frame size as configured with
HttpClientOptions.setMaxWebsocketFrameSize(int)
then Vert.x will split it into multiple WebSocket frames before sending it on the wire.
==== Writing frames to WebSockets
A WebSocket message can be composed of multiple frames. In this case the first frame is either a _binary_ or _text_ frame
followed by zero or more _continuation_ frames.
The last frame in the message is marked as _final_.
To send a message consisting of multiple frames you create frames using
WebSocketFrame.binaryFrame(io.vertx.core.buffer.Buffer, boolean)
, WebSocketFrame.textFrame(java.lang.String, boolean)
or
WebSocketFrame.continuationFrame(io.vertx.core.buffer.Buffer, boolean)
and write them
to the WebSocket using WebSocket.writeFrame(io.vertx.core.http.WebSocketFrame)
.
Here's an example for binary frames:
[source,$lang]
----
examples.HTTPExamples#example56
----
In many cases you just want to send a websocket message that consists of a single final frame, so we provide a couple
of shortcut methods to do that with WebSocket.writeFinalBinaryFrame(io.vertx.core.buffer.Buffer)
and WebSocket.writeFinalTextFrame(String)
.
Here's an example:
[source,$lang]
----
examples.HTTPExamples#example56_1
----
==== Reading frames from WebSockets
To read frames from a WebSocket you use the WebSocket.frameHandler(io.vertx.core.Handler)
.
The frame handler will be called with instances of WebSocketFrame
when a frame arrives,
for example:
[source,$lang]
----
examples.HTTPExamples#example57
----
==== Closing WebSockets
Use WebSocketBase.close()
to close the WebSocket connection when you have finished with it.
==== Streaming WebSockets
The WebSocket
instance is also a ReadStream
and a
WriteStream
so it can be used with pumps.
When using a WebSocket as a write stream or a read stream it can only be used with WebSockets connections that are
used with binary frames that are no split over multiple frames.
=== Using a proxy for HTTP/HTTPS connections
The http client supports accessing http/https URLs via a HTTP proxy (e.g. Squid) or _SOCKS4a_ or _SOCKS5_ proxy.
The CONNECT protocol uses HTTP/1.x but can connect to HTTP/1.x and HTTP/2 servers.
Connecting to h2c (unencrypted HTTP/2 servers) is likely not supported by http proxies since they will support
HTTP/1.1 only.
The proxy can be configured in the HttpClientOptions
by setting a
ProxyOptions
object containing proxy type, hostname, port and optionally username and password.
Here's an example of using an HTTP proxy:
[source,$lang]
----
examples.HTTPExamples#example58
----
When the client connects to an http URL, it connects to the proxy server and provides the full URL in the
HTTP request ("GET http://www.somehost.com/path/file.html HTTP/1.1").
When the client connects to an https URL, it asks the proxy to create a tunnel to the remote host with
the CONNECT method.
For a SOCKS5 proxy:
[source,$lang]
----
examples.HTTPExamples#example59
----
The DNS resolution is always done on the proxy server, to achieve the functionality of a SOCKS4 client, it is necessary
to resolve the DNS address locally.
=== Automatic clean-up in verticles
If you're creating http servers and clients from inside verticles, those servers and clients will be automatically closed
when the verticle is undeployed.Copyright © 2016. All rights reserved.