代码编织梦想

Writing HTTP servers and clients
上一章介绍了 tcp服务端和客户端,本章介绍怎么使用vertx创建无阻塞的http服务端和客户端。

Creating an HTTP Server

使用vertx可以很简单的创建一个http的服务端:

HttpServer server = vertx.createHttpServer();

Configuring an HTTP server

可以使用HttpServerOptions对象类配置http 服务端。

HttpServerOptions options = new HttpServerOptions().setMaxWebsocketFrameSize(1000000);
HttpServer server = vertx.createHttpServer(options);

Start the Server Listening

可以使用无参数的listen方法:

HttpServer server = vertx.createHttpServer();
server.listen();

也可以使用有参数的listen方法:

HttpServer server = vertx.createHttpServer();
server.listen(8080, "myhost.com");

默认的地址是0.0.0.0,意味着监听所有可用的一切地址。默认的端口是80.

监听完成后的动作,可以指定handler来响应。

HttpServer server = vertx.createHttpServer();
server.listen(8080, "myhost.com", res -> {
  if (res.succeeded()) {
    System.out.println("Server is now listening!");
  } else {
    System.out.println("Failed to bind!");
  }
});

Getting notified of incoming requests

获取一个进来的请求通知。

HttpServer server = vertx.createHttpServer();
server.requestHandler(request -> {
  // Handle the request in here
});

Handling requests

当一个请求到达时,request handler会被调用,并传入一个httprequest参数。
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.
当request的header全部读取完毕后,就会调用request handler。
如果一个request包含一个比较大的body时,这个body有可能会在调用request handler后才完整的读入到server中。
通过request对象,你可以获取到uri, path, params and headers等。
每一次request都有一个绑定的response对象,可以通过response()方法获取到。

vertx.createHttpServer().requestHandler(request -> {
  request.response().end("Hello world");//获取response对象,并返回hello world字符串
}).listen(8080);

Request version

通过version方法获取。

Request method

通过method方法获取(GET, POST, PUT, DELETE, HEAD, OPTIONS, etc)。

Request URI

Use 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.
获取相对的URI地址。

Request path

Use path to return the path part of the URI

For example, if the request URI was:
a/b/c/page.html?param1=abc&param2=xyz

Then the path would be
/a/b/c/page.html

Request query

Use query to return the query part of the URI
使用query方法获取请求的uri参数部分
For example, if the request URI was:
a/b/c/page.html?param1=abc&param2=xyz

Then the query would be
param1=abc&param2=xyz

Request headers

使用headers方法获取请求的头部。其将会返回MultiMap的实例。

MultiMap headers = request.headers();

// Get the User-Agent:
System.out.println("User agent is " + headers.get("user-agent"));

// You can also do this and get the same result:
System.out.println("User agent is " + headers.get("User-Agent"));

Request parameters

使用params来获取请求的参数。和headers类似,返回的是MultiMap的实例。
For example if the URI was:
/page.html?param1=abc&param2=xyz

Then the parameters would contain the following:
param1: ‘abc’
param2: ‘xyz

注意:当提交一个multi-part/form-data的form表单时,这种方法是不能获取到参数的。

Remote address

请求的地址可以使用remoteAddress方法获取。

Absolute URI

使用absoluteURI获取绝对地址。

End handler

当整个请求内容(包含body)读取完毕后,会调用endHandler方法。

Reading Data from the Request Body

一般情况下,一个请求都会带有一个body。如前文说讲,request handler可能在body还没有被读取完成之前就被调用。这是因为一个body可能会很大,因此我们在将body交给你之前不会将整个body放到缓冲区中,这样做的话有可能导致内存用尽。
为了接收body,我们可以使用handler方法。body的一个块(a chunk)到达时就会调用这个方法。

request.handler(buffer -> {
  System.out.println("I have received a chunk of the body of length " + buffer.length());
});

此方法会被调用几次,这取决于你的body的大小。
如果你的body不是很大,那么你可以使用下面的代码:

Buffer totalBuffer = Buffer.buffer();

request.handler(buffer -> {
  System.out.println("I have received a chunk of the body of length " + buffer.length());
  totalBuffer.appendBuffer(buffer);
});

request.endHandler(v -> {
  System.out.println("Full body received, length = " + totalBuffer.length());
});

这是一个很普遍的现象。因此,vertx提供了bodyHandler方法,用来达到上面代码的功能。当body读取完成后,就会调用bodyHandler。

Pumping(泵) requests

The request object is a ReadStream so you can pump the request body to any WriteStream instance。
request对象是一个ReadStream (读流),因此可以将request body泵入到任何WriteStream (写流)中。

Handling HTML forms

提交的form的type可以是 application/x-www-form-urlencoded 或者multipart/form-data中的一个。

For url encoded forms, the form attributes are encoded in the url, just like normal query parameters.
对于application/x-www-form-urlencoded这种类型的form表单,form数据将会编码到url中,就像一个普通的查询参数一样。

For multi-part forms they are encoded in the request body, and as such are not available until the entire body has been read from the wire.
Multi-part forms can also contain file uploads.
对于multipart/form-data类型的form表单,form数据会被编码到request body中,并且在整个body没有读完之前是不可用的。
这种类型的表单也包含文件的上传。

If you want to retrieve the attributes of a multi-part form you should tell Vert.x that you expect to receive such a form before any of the body is read by calling setExpectMultipart with true, and then you should retrieve the actual attributes using formAttributes once the entire body has been read:
为了获取 multi-part类型的form数据,你需要,在接收body的任何数据之前通过调用setExpectMultipart 方法(参数为true),告诉vertx,你期望接收这样一个form。当整个body读取完成后,可以使用formAttributes 方法来回去actual attributes。如下代码:

server.requestHandler(request -> {
  request.setExpectMultipart(true);
  request.endHandler(v -> {
    // The body has now been fully read, so retrieve the form attributes
    MultiMap formAttributes = request.formAttributes();
  });
});

Handling form file uploads

为了接收上传的文件,需要设置form type为multi-part 和 设置一个 uploadHandler (request 上)。每次上传到达时,都会调用uploadHandler (参数为HttpServerFileUpload的实例)。

server.requestHandler(request -> {
  request.setExpectMultipart(true);
  request.uploadHandler(upload -> {
    System.out.println("Got a file upload " + upload.name());
  });
});

vertx没有提供完整的buffer包含整个上传内容。相反的,上传的内容只是分段的接收:

request.uploadHandler(upload -> {
  upload.handler(chunk -> {
    System.out.println("Received a chunk of the upload of length " + chunk.length());
  });
});

request对象是一个ReadStream (读流),因此可以将request body泵入到任何WriteStream (写流)中。

如果你想将上传文件写入到磁盘上,你可以调用streamToFileSystem方法:

request.uploadHandler(upload -> {
  upload.streamToFileSystem("myuploads_directory/" + upload.filename());
});

Sending back responses

返回响应

response object 是 HttpServerResponse的实例。可以通过request.response()获取。可以通过response对象返回响应的数据。

Setting status code and message

设置状态码和消息

响应的状态码默认为200,表现形势为OK。
可以使用setStatusCode方法改变响应的状态码。
也可以使用自定义的状态消息,可以通过setStatusMessage方法来定义。
如果没有指定一个状态消息,一个默认合适的状态码将会被使用。

Writing HTTP responses

使用response对象的write方法可以给响应返回数据。
在response结束之前,write方法可以被调用多次。

HttpServerResponse response = request.response();
response.write(buffer);//写入一个buffer
        .write("hello world!");//写入一个字符串
        .write("hello world!", "UTF-16");//按特定的编码写入一个字符串

向response中写入数据之后,会立即的返回。然后向前端传送数据是需要排队的。将一个response结束,需要调用end方法。

响应头首先会被写入响应中,因此如果我们们有按响应块(using HTTP chunking)来传输的话,就需要在响应头中设置Content-Length信息。否则的话,就有可能在响应还没有传输完成就关闭了连接。

Ending HTTP responses

使用end方法来结束响应。

HttpServerResponse response = request.response();
response.write("hello world!");
response.end();

当然也可以这样使用:

HttpServerResponse response = request.response();
response.end("hello world!");

Closing the underlying connection

调用close方法来关闭底层连接。
Keep-alive connections不会自动的去关闭底层连接,如果希望在超过空闲的时间后(idle time),自动的去关闭连接,可以调用方法setIdleTimeout去配置。

Setting response headers

设置响应头部的两种方式:

HttpServerResponse response = request.response();
MultiMap headers = response.headers();
headers.set("content-type", "text/html");
headers.set("other-header", "wibble");

或者

HttpServerResponse response = request.response();
response.putHeader("content-type", "text/html").putHeader("other-header", "wibble");

Chunked HTTP responses and trailers

分块的响应和追踪

这将允许响应进行分块的写入。这一般用在有大的响应body中,或者提前不能知道的响应流中。

HttpServerResponse response = request.response();
response.setChunked(true);//设置响应进行分块传输

默认是不分块。在分块模式,每次调用一个写方法会产生一个新的HTTP块被写出来。
在分块模式,你也可以写HTTP响应追踪到响应中。这些实际上是在响应的最后一块中(in the final chunk of the response)。
To add trailers to the response, add them directly to the trailers.

HttpServerResponse response = request.response();
response.setChunked(true);
MultiMap trailers = response.trailers();
trailers.set("X-wibble", "woobble").set("X-quux", "flooble");

or

HttpServerResponse response = request.response();
response.setChunked(true);
response.putTrailer("X-wibble", "woobble").putTrailer("X-quux", "flooble");

Serving files directly from disk or the classpath

你也可以将本地磁盘或者classpath下的文件作为响应的内容返回,在vertx中这是异步的,调用AsyncFile方法,并将流泵入到响应中。
你也可以使用readFile方法来加载文件,然后将其写入到response中。
当然也可以通过sendFile来达到相同的目的,尤其是在大文件的情况下,效率会很好,小文件的情况下,效率可能会有点慢。

vertx.createHttpServer().requestHandler(request -> {
  String file = "";
  if (request.path().equals("/")) {
    file = "index.html";
  } else if (!request.path().contains("..")) {
    file = request.path();
  }
  request.response().sendFile("web/" + file);//发送文件
}).listen(8080);

sendFile是异步的,如果你需要监听,也可以在sendFile后面增加一个handler的参数。
如下的例子,说明的是sendFile发送文件的一部分数据:

vertx.createHttpServer().requestHandler(request -> {
  long offset = 0;
  try {
    offset = Long.parseLong(request.getParam("start"));//起始位置
  } catch (NumberFormatException e) {
    // error handling...
  }

  long end = Long.MAX_VALUE;//结束位置
  try {
    end = Long.parseLong(request.getParam("end"));
  } catch (NumberFormatException e) {
    // error handling...
  }

  request.response().sendFile("web/mybigfile.txt", offset, end);//发送从起始位置到结束位置中间部分的内容。
}).listen(8080);

当然end是可以省略的,表明到文件的结尾

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.
服务端的response是一个WriteStream(写入流),因此你可以泵入任何的ReadStream(读入流)。

vertx.createHttpServer().requestHandler(request -> {
  HttpServerResponse response = request.response();
  if (request.method() == HttpMethod.PUT) {
    response.setChunked(true);
    Pump.pump(request, response).start();//将request泵入到response
    request.endHandler(v -> response.end());
  } else {
    response.setStatusCode(400).end();
  }
}).listen(8080);

这是一个例子,是将所有的put方法请求的内容在返回回去。

HTTP Compression(压缩)

使用setCompressionSupported来开启压缩。(不知道压缩有什么作用的请自行度娘)。默认情况不开启压缩。通常使用的格式为deflate and gzip。

Creating an HTTP client

使用默认的参数创建:

HttpClient client = vertx.createHttpClient();

也可以使用HttpClientOptions 配置参数:

HttpClientOptions options = new HttpClientOptions().setKeepAlive(false);
HttpClient client = vertx.createHttpClient(options);

Making requests

向服务端发起请求。
可以复用httpclient。
向同一个host和port发起请求:

HttpClientOptions options = new HttpClientOptions().setDefaultHost("wibble.com");
// Can also set default port if you want...
HttpClient client = vertx.createHttpClient(options);
client.getNow("/some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
});

向不同的host或者port发起请求:

HttpClient client = vertx.createHttpClient();

// Specify both port and host name
client.getNow(8080, "myserver.mycompany.com", "/some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
});

// This time use the default port 80 but specify the host name
client.getNow("foo.othercompany.com", "/other-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
});

Simple requests with no request body

HTTP三种请求的方式 GET, OPTIONS and HEAD requests—可以使用xxxNow方法请求(getNow、optionNow、headNow)。

HttpClient client = vertx.createHttpClient();

// Send a GET request
client.getNow("/some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
});

// Send a GET request
client.headNow("/other-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
});

Writing general requests

有的时候我们不会到我们需要使用何种的请求方式。因此我们提供了request的方法来完成:

HttpClient client = vertx.createHttpClient();

client.request(HttpMethod.GET, "some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
}).end();

client.request(HttpMethod.POST, "foo-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
}).end("some-data");

Writing request bodies

post方式的请求是有body的。使用下面的方式来添加body。

HttpClient client = vertx.createHttpClient();

HttpClientRequest request = client.post("some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
});

// Now do stuff with the request
request.putHeader("content-length", "1000");
request.putHeader("content-type", "text/plain");
request.write(body);

// Make sure the request is ended when you're done with it
request.end();

Or fluently:

client.post("some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
}).putHeader("content-length", "1000").putHeader("content-type", "text/plain").write(body).end();

Or event more simply:

client.post("some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
}).putHeader("content-type", "text/plain").end(body);

存在的方法使用的是utf-8的编码,如果需要指定其他格式的编码,可以使用:

request.write("some data");

// Write string encoded in specific encoding
request.write("some other data", "UTF-16");//使用UTF-16编码

// Write a buffer
Buffer buffer = Buffer.buffer();
buffer.appendInt(123).appendLong(245l);
request.write(buffer);

如果只是需要写入一次数据,可以调用有参数的end方法:

request.end("some simple data");

// Write buffer and end the request (send it) in a single call
Buffer buffer = Buffer.buffer().appendDouble(12.34d).appendLong(432l);
request.end(buffer);

还有一点需要注意的是,跟服务端的响应一样,如果客户端的请求有较大的请求体,如果没有做chunks操作,那么就需要在head中指定Content-Length参数。否则的可以会出现异常。

Writing request headers

参考如下代码:

MultiMap headers = request.headers();
headers.set("content-type", "application/json").set("other-header", "foo");

或者:

request.putHeader("content-type", "application/json").putHeader("other-header", "foo");

Ending HTTP requests

调用end方法结束http request。

request.end();

或者

request.end("some-data");

// End it with a buffer
Buffer buffer = Buffer.buffer().appendFloat(12.3f).appendInt(321);
request.end(buffer);

Chunked HTTP requests

setChunked(true);
默认是不做chunk的。
如果不做chunk,最好在头部中加入Content-Length参数。

request.setChunked(true);

// Write some chunks
for (int i = 0; i < 10; i++) {
  request.write("this-is-chunk-" + i);
}

request.end();

Request timeouts

setTimeout method

Handling exceptions

注册一个exception handler来监听,参数为HttpClientRequest的实例。

HttpClientRequest request = client.post("some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
});
request.exceptionHandler(e -> {
  System.out.println("Received exception: " + e.getMessage());
  e.printStackTrace();
});

上面的例子exceptionHandler不接收响应状态码为2xx的。
如果需要可以如下处理:

HttpClientRequest request = client.post("some-uri", response -> {
  if (response.statusCode() == 200) {
    System.out.println("Everything fine");
    return;
  }
  if (response.statusCode() == 500) {
    System.out.println("Unexpected behavior on the server side");
    return;
  }
});
request.end();

note:XXXNow methods cannot receive an exception handler.

Specifying a handler on the client request

在客户端请求上指定一个handler。

当请求被创建时,你可以使用handler方法来注册一个方法。

HttpClientRequest request = client.post("some-uri");
request.handler(response -> {
  System.out.println("Received response with status code " + response.statusCode());
});

Using the request as a stream

将request作为一个stream

client request请求是一个WriteStream。因此你可以将任何ReadStream泵入到client request中。

request.setChunked(true);
Pump pump = Pump.pump(file, request);
file.endHandler(v -> request.end());
pump.start();

Handling http responses 处理响应

在handler中,会接收到一个HttpClientResponse的实例。从这个实例中,你可以查询到status code 和 status message 使用方法 statusCode 和statusMessage.

client.getNow("some-uri", response -> {
  // the status code - e.g. 200 or 404
  System.out.println("Status code is " + response.statusCode());

  // the status message e.g. "OK" or "Not Found".
  System.out.println("Status message is " + response.statusMessage());
});

Using the response as a stream

response是一个ReadStream,因此你可以将其泵入到任何WriteStream中。

Response headers and trailers

使用headers方法可以获取response的头部信息。

String contentType = response.headers().get("content-type");
String contentLength = response.headers().get("content-lengh");

使用trailers方法可以获取response的trailers信息。Trailers are also a MultiMap。

Reading the request body

读取响应内容

client.getNow("some-uri", response -> {
  //获取响应内容
  response.handler(buffer -> {
    System.out.println("Received a part of the response body: " + buffer);
  });
});

如果响应体很大,可以如下操作:

client.getNow("some-uri", response -> {

  // Create an empty buffer
  Buffer totalBuffer = Buffer.buffer();

  response.handler(buffer -> {
    System.out.println("Received a part of the response body: " + buffer.length());

    totalBuffer.appendBuffer(buffer);
  });

  response.endHandler(v -> {
    // Now all the body has been read
    System.out.println("Total response body length is " + totalBuffer.length());
  });
});

或者,你可以直接这样:

client.getNow("some-uri", response -> {

  response.bodyHandler(totalBuffer -> {
    // Now all the body has been read
    System.out.println("Total response body length is " + totalBuffer.length());
  });
});

Response end handler

使用endHandler注册

Reading cookies from the response

使用cookies方法。
或者
you can just parse the Set-Cookie headers yourself in the response.

100-Continue handling

何为100-Continue???
来自网上的解释:
在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为俩步,
1. 发送一个请求, 包含一个Expect:100-continue, 询问Server使用愿意接受数据
2. 接收到Server返回的100-continue应答以后, 才把数据POST给Server
这是libcurl的行为.

于是,这样就有了一个问题, 并不是所有的Server都会正确应答100-continue, 比如lighttpd, 就会返回417 “Expectation Failed”, 则会造成逻辑出错。

不过多解释,直接上代码:

1 客户端代码:

HttpClientRequest request = client.put("some-uri", response -> {
  System.out.println("Received response with status code " + response.statusCode());
});
//设置Expect:100-Continue头部
request.putHeader("Expect", "100-Continue");
//使用continueHandler注册handler,用来完成后续动作
request.continueHandler(v -> {
  // OK to send rest of body
  request.write("Some data");
  request.write("Some more data");
  request.end();
});

2 服务端代码:

httpServer.requestHandler(request -> {
  //判断是否为Expect:100-Continue头部
  if (request.getHeader("Expect").equalsIgnoreCase("100-Continue")) {

    // Send a 100 continue response
    request.response().writeContinue();

    // The client should send the body when it receives the 100 response
    request.bodyHandler(body -> {
      // Do something with body
    });

    request.endHandler(v -> {
      request.response().end();
    });
  }
});

当然,服务端可以拒接接收后面的body内容:

httpServer.requestHandler(request -> {
  if (request.getHeader("Expect").equalsIgnoreCase("100-Continue")) {
    //
    boolean rejectAndClose = true;
    if (rejectAndClose) {

      // Reject with a failure code and close the connection
      // this is probably best with persistent connection
      request.response()
          .setStatusCode(405)
          .putHeader("Connection", "close")
          .end();
    } else {

      // Reject with a failure code and ignore the body
      // this may be appropriate if the body is small
      request.response()
          .setStatusCode(405)
          .end();
    }
  }
});

Enabling compression on the client

客户端数据压缩。默认是不压缩的。
需要压缩可以使用setTryUseCompression方法。

Pooling and keep alive

setKeepAlive—-可以让客户端和服务端保持连接。
setIdleTimeout—-可以设置客户端空闲多长时间后断开连接。
setMaxPoolSize—-可以设置最大开启多少个连接池。

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 setPipelining. By default pipe-lining is disabled.

When pipe-lining is enabled requests will be written to connections without waiting for previous responses to return.

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:

vertx.createHttpServer().requestHandler(request -> {
  request.response().end("Hello from server " + this);
}).listen(8080);

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:

vertx.setPeriodic(100, (l) -> {
  vertx.createHttpClient().getNow(8080, "localhost", "/", resp -> {
    resp.bodyHandler(body -> {
      System.out.println(body.toString("ISO-8859-1"));
    });
  });
});

Vert.x delegates the requests to one of the server sequentially:

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

参照TCP ssl的配置。

WebSockets

在服务端有两种方式配置websocket:

WebSocket handler

第一种方式:
使用websocketHandler来注册websocket 的 handler。 handler的参数为ServerWebSocket的实例。

server.websocketHandler(websocket -> {
  System.out.println("Connected!");
});

也可以拒接接收websocket :

server.websocketHandler(websocket -> {
  if (websocket.path().equals("/myapi")) {
    websocket.reject();
  } else {
    // Do something
  }
});

第二种方式: Upgrading to WebSocket
upgrade方法。

server.requestHandler(request -> {
  if (request.path().equals("/myapi")) {

    ServerWebSocket websocket = request.upgrade();//将请求升级
    // Do something

  } else {
    // Reject
    request.response().setStatusCode(400).end();
  }
});

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

客户端websocket配置:

client.websocket("/some-uri", websocket -> {
  System.out.println("Connected!");
});

Writing messages to WebSockets

使用websocket发送消息:

Buffer buffer = Buffer.buffer().appendInt(123).appendFloat(1.23f);

websocket.writeBinaryMessage(buffer);

如果websocket发送的数据过大,比setMaxWebsocketFrameSize方法设置的还要大,vertx将会将其拆分多个frames发送。

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 , WebSocketFrame.textFrame or WebSocketFrame.continuationFrame and write them to the WebSocket using writeFrame.

Here’s an example for binary frames:

WebSocketFrame frame1 = WebSocketFrame.binaryFrame(buffer1, false);
websocket.writeFrame(frame1);

WebSocketFrame frame2 = WebSocketFrame.continuationFrame(buffer2, false);
websocket.writeFrame(frame2);

// Write the final frame
WebSocketFrame frame3 = WebSocketFrame.continuationFrame(buffer2, true);
websocket.writeFrame(frame3);

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 writeFinalBinaryFrame and writeFinalTextFrame.

Here’s an example:

websocket.writeFinalTextFrame("Geronimo!");

// Send a websocket messages consisting of a single final binary frame:

Buffer buff = Buffer.buffer().appendInt(12).appendString("foo");

websocket.writeFinalBinaryFrame(buff);

Reading frames from WebSockets

websocket.frameHandler(frame -> {
  System.out.println("Received a frame of size!");
});

Closing WebSockets

close方法

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.

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.

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/avastxa/article/details/50717880

netty报错:max frame length of 65536 has been exceeded 的解决_小明同学yyds的博客-爱代码爱编程

使用netty网络通信。出现收到数据包差超过设置值。这里通过源码分析下以及解决思路 错误重现原因解决 错误重现 io.netty.handler.codec.Corr

vertx简单表单上传_淹死的鱼pp的博客-爱代码爱编程

我正在使用vertx简单的表单上传。当我上传单个文件时工作正常。如果表单具有“多个”输入并选择多个文件,则HTTPServerUpload出现错误“响应已被写入(java.lang.IllegalStateException: Response has already been written)”。由于响应在第一个文件的末端处理程序中结束,因此它将为后续文

vert.x(vertx) web开发-路由_jhappyfly的博客-爱代码爱编程_vertx web

在Vert.x 创建HTTP服务 中我们已经创建了一个简单的HttpServer,但这个HttpServer比较低级,对于请求参数解析、Session等常用功能都需要我们通过编码实现,也就是要重复造轮子,非常不方便。 Vert.x提供了Web开发组件vertx-web,提供了一堆Web开发中常用的功能。比如参数封装,路由,国际化,认证和授权,sessio

vert.x(vertx)发送 http/https请求_jhappyfly的博客-爱代码爱编程_vertx https

应用场景 在应用系统中,经常会有类似于获取天气、发送短信、处理图像、支付等需求,这些需求实现都非常复杂,或者受到监管的限制,不是任何一个公司都可以做到的。但有些应用为了提升用户的体验,需要用到这些功能,比如饿了么会根据你所在的位置推荐附近的商家,在线商城需要在线支付,还有一些应用需要进行人脸识别等等。 有需求就会有市场,于是就有很多的公司单独对外提

修改spring-cloud-gateway中websocket的Max frame length-爱代码爱编程

修改spring-cloud-gateway中websocket的Max frame length(默认64K) 在项目中发现spring微服推送websocket消息超过60多KB的时候,websocket连接中断,微服并没有异常日志输出,查看spring-cloud-gateway网关发现一条warn日志 An exception has been

vertx实现简单的反向代理-爱代码爱编程

一提到反向代理,我们首先想到的或许是nginx,但某些场景,我们不能随意的去搭建一个NG。如果我们此时只有一个JavaWeb项目可用,或许最好的办法,就是在已有项目中集成一个反向代理服务。 所以我们就需要用Java手写一个简单的反向代理。 语言:Java技术框架:Vert.x代理:TCP反向代理例子描述 本机暴露8088端口,外部客户端访问该端口的连

spring cloud gateway修改websocket的Max Frame length传输大小-爱代码爱编程

参考:https://blog.csdn.net/wu_xijie/article/details/103166605 spring cloud版本:Greenwich.SR2 spring cloud gateway使用默认的netty 使用websocket,通过spring cloud gateway转发传送数据大于64kb时会报错,查看资料发

使用Vert.x进行响应式开发-爱代码爱编程

最近,似乎我们正在听到有关Java的最新和最好的框架的消息。 忍者 , SparkJava和Play等工具; 但是每个人都固执己见,使您感到您需要重新设计整个应用程序以利用它们的出色功能。 这就是为什么当我发现Vert.x时令我感到宽慰的原因。 Vert.x不是一个框架,它是一个工具包,它不受质疑,而且正在解放。 Ve

使用Vert.x异步下载文件的服务端和客户端-爱代码爱编程

使用Vert.x方便的进行文件的异步下载,为了更加方便,这里使用groovy。(java同理) 服务端,提供文件的下载import io.vertx.core.Vertx import io.vertx.ext.web.Router def vertx = Vertx.vertx() def server = vertx.createHttpServe

vert.x java post请求无法接收到post请求body中的参数-爱代码爱编程

最近才了解到这个框架vert.x,这个框架在我看来是很不错的。 1.首先基于netty,这个优点就不说了。 2.异步非阻塞的网络框架。 3.轻量级框架,启动真的是超级快,如果你用过spring的框架,对比之下就会发现它有多轻量。 4.支持各种插件,redis guice 以及graphql(说实话还有很多很多,就不一一列举了。) 5.官方对于每个插件都给

vertx web client 接收文件上传file-uploads及删除上传文件-爱代码爱编程

最近在弄一个vertx的小项目,最近的一点小记录。。。 vertx post上传文件参数,是需要特殊处理一下的,开始以为用routingContext的getBody就能都获取到,后来翻文档发现这么一句If you want to upload files and send attributes, you can create a MultipartFo

路由器java灯一直闪_java – Vertx的路由器问题-爱代码爱编程

早上好, 我从Vertx for java开始,我想创建路由示例,所以我复制过去的行,但似乎在Router.router(顶点)中出现了问题: The type io.vertx.rxjava.core.Vertx cannot be resolved. It is indirectly referenced from required .cla

Vert.x实战 异步数据和事件流-爱代码爱编程

本章包括: 为什么流【streams】是事件【eventing】之上的一个有用的抽象什么是背压【back-pressure】,为什么它是异步生产者和消费者的基础如何从流【streams】中解析协议数据到目前为止,我们一直在使用回调【callbacks】来处理事件,这些回调来自各种来源,例如HTTP或TCP服务器。回调【Callbacks 】使我们可以一次

vertx访问html,Vert.x HTTP 服务器与客户端-爱代码爱编程

编写HTTP 服务器与客户端 Vert.x让编写非阻塞的HTTP 服务器与客户端变得非常轻松。 创建HTTP 服务器 缺省状况: HttpServer server = vertx.createHttpServer(); 配置HTTP 服务器 HttpServerOptions options = new HttpServerOptions

简单测试Content-Length和Chunked两种不同的数据传输方式-爱代码爱编程

文章目录 一、代码测试1、前期准备2、测试Content-length3、测试Transfer-Encoding:chunked二、tomcat源码1、Request过程2、其他 Content-Length:按照数据长度进行数据传输 Chunk:按照块进行数据传输 如下图的样例请求,只是此时的Content-length为响应