获取定制的HTTP/2帧
HTTP/2是HTTP请求响应模型多帧协议。协议允许其他类型帧发送和接收。为了接收定制帧,应访在请求上应用customFrameHandler。这会在每当定制帧到达时会被调用。这里有个例子:
request.customFrameHandler(frame -> {
System.out.println("Received a frame type=" + frame.type() +
" payload" + frame.payload().toString());
});
HTTP/2帧不受流控制-在定制帧收到(无论请求是暂停还是继续)时,帧处理器都将被立即调用。
非标准的HTTP方法
OTHER HTTP方法被用是一种非标准方法,在此情况下rawMethod返回客户端发送的HTTP方法。
发回响应
服务器响应对象是HttpServerResponse的实例并且被包含在请求对象中。可以使用请求对象向客户端发送响应数据。
设置状态吗与消息
默认的响应状态码是200,代表OK。调用setStatusCode设置不同的编码。通过setStatusMessage方法可以指定特定的状态消息。如果不想指定状态消息,将使用一个默认的状态码消息响应到客户 端。
注意:对于HTTP/2 状态不在响应中表现,因为协议不会将消息转递到客户端。
向HTTP响应中写数据
为了向HTTP响应中写数据,请使用write操作之一进行数据回写。在响应结束之前,写入操作可以调用多次。写入操作也有多种调用形式。
HttpServerResponse response =request.response();
response.write(buffer);
写入字符串,这此情况,字符中将采用UTF-8编码然后被写到客户端
HttpServerResponse response =request.response();。因
response.write("hello world!");
写入指定编码的字符串,在此情 况下,字符串将使用指定的编码格式进行编码然后写回客户端:
HttpServerResponse response =request.response();
response.write("hello world!","UTF-16");
向响应写数据是异步的,并在写到发送队列后立既返回。
如果你仅想写一个字符串或者缓存到HTTP响应,你在写 完后可以调用end方法结束响应对象。
第一个调用写回的响应头。顺序的,如果你没有使用HTTP块,然后你必须在写回数据前设置Content-Length头,否则会有延迟。如果你使用HTTP块,也就不必担心了。
结束HTTP响应
一旦你完成HTTP响应,你应当结带它(end
关闭有多个法,不带参数的end方法,响应会简单关闭。
HttpServerResponse response =request.response();
response.write("hello world!");
response.end();
也可调用带字符串或者缓冲器的关闭方法,与write方法类似。在这种情况下,相当于调用写字符串或缓冲器后接着调用不带参数的end方法,例如:
HttpServerResponse response =request.response();
response.end("hello world!");
关闭潜在的连接(这里指TCP连接)
可以用close方法关闭TCP连接(即Socket连接),非长连接将会在响应结束后由Vert.x自动关闭。长连接默认不会由Vert.x自动关闭。如果在空闭一段时间后,你想长连接被关闭,请配置空闭超时参数setIdleTimeout.
HTTP/2连接在关闭响应前发送GOAWAY帧。
设置响应头
HTTP响应头可以能过直接添加到headers中加到响应中去:
HttpServerResponse response =request.response();
MultiMap headers = response.headers();
headers.set("content-type","text/html");
headers.set("other-header","wibble");
或者用putHeader方法添加
HttpServerResponse response = request.response();
response.putHeader("content-type","text/html").putHeader("other-header", "wibble");
头必须添加在响应体任意部分被写回之前。
块HTTP响应的传输
Vert.x支持HTTP块传输编码。
这就可能使用块的方式将HTTP响应体写回,这很常用,因为在大的响应体写回到客户端时,响应体的大小不能预先知道。
使用下面的代码,采用块模式将HTTP响应写回:
HttpServerResponse response = request.response();
response.setChunked(true);
默认是非块的写回方式,在块模式下,每调用一次write方法,就会产生一个新的HTTP块被写出。
在用块模式时,可以将HTTP响应 trailers头写到响应尾部。这些将实际被写入到最后一个块。
注意:块响应对于HTTP/2流无效果。
为了添加到响应,可以真接添加到trailers.
HttpServerResponse response =request.response();
response.setChunked(true);
MultiMap trailers = response.trailers();
trailers.set("X-wibble","woobble").set("X-quux", "flooble");
或者使用 putTrailer.
HttpServerResponse response =request.response();
response.setChunked(true);
response.putTrailer("X-wibble","woobble").putTrailer("X-quux", "flooble");
直接从磁盘或类路径读取文件并向外服务
如果你在编写一个web服务器,一个对外提供文件的方法是从磁盘读取作为一个AsyncFile并且泵接到HTTP响应。或者使用readFile加载并且直接写到响应中去。作为替代方法,Vert.x提供了一个方法,此方法允许你从磁盘或者文件系统向http响应中提供文件。这需要底层的操作系统的支持,因为这会导至操作系统直接从文件将字节传递给SOCKET,而根本不会通过用户空间。
这是通过调用sendFile实现的,对大文件通常很高效,对小文件相对会慢一些。这里有一个简单的web服务器,仅用sendFile方法向对提供文件服务。
vertx.createHttpServer().requestHandler(request-> {
Stringfile = "";
if(request.path().equals("/")) {
file= "index.html";
} elseif (!request.path().contains("..")) {
file= request.path();
}
request.response().sendFile("web/" + file);
}).listen(8080);
发送一个文件是异步的不会立既完成,所以在调用发送文件方法返回后需要一段时间。如果想在文件写完成时得到通知,可以使用sendFile.
注意:如果使用HTTPS式的sendFile,文件将会复制到用户空间,因为如果操作系统内核直接从磁盘复制数据到socket,我们将失去对数据进行加密的机会。
警示:如果你直接使用Vert.x编写web服务器,请记住,用户不能浏览访问文件路径之外的路径,这反而比Vert.x Web更加安全。
在需要向外提供一个文件的一部分时,可以从给定的字节处开始,可这样做:
vertx.createHttpServer().requestHandler(request-> {
longoffset = 0;
try {
offset = Long.parseLong(request.getParam("start"));
} catch(NumberFormatException e) {
//error handling...
}
longend = 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);
如果希望从一个偏移量发送文件内容直到文件结束,基实不需长度,这种情况下,可以这样做:
vertx.createHttpServer().requestHandler(request-> {
longoffset = 0;
try {
offset = Long.parseLong(request.getParam("start"));
} catch(NumberFormatException e) {
//error handling...
}
request.response().sendFile("web/mybigfile.txt", offset);
}).listen(8080);
泵接响应
服务器响应是一个写入流(WriteStream)实例,所以可从其他读取流(ReadStream)进行泵接,例如AsyncFile,NetSocket,WebSocket或者HttpServerRequest.
这是一个仅用对HTTP put方使用将请求体回写给客户端的例子,例子就泵接了request,response传递请求体。因此对于很大的甚至内存不能适应的请求体也能工作:
vertx.createHttpServer().requestHandler(request-> {
HttpServerResponse response = request.response();
if(request.method() == HttpMethod.PUT) {
response.setChunked(true);
Pump.pump(request, response).start();
request.endHandler(v -> response.end());
} else{
response.setStatusCode(400).end();
}
}).listen(8080);
编写HTTP/2帧
HTTP/2是一个针对HTTP请求/响应模式的多帧协议。协议允许发送和接收不同种类的帧。为了使用这此帧,请在响应上用writeCustomFrame方法。下面是一个例子:
int frameType = 40;
int frameStatus = 10;
Buffer payload = Buffer.buffer("somedata");
// Sending a frame to the client
response.writeCustomFrame(frameType,frameStatus, payload);
这此帧被立即发送,并不受流控制,意思是在这样帧被发送,可以在其他数据帧之前。
流得重置
HTTP/1.x不允行一个请求或者响应流重置,例如,当客户端上传的资源已经存在于服务器上,服务器需要接收完整的响应。
在请求响应过程中,HTTP/2在任何时候都支持流重置:
request.response().reset();
重置时,默认的NO_ERROR (0) 错误码会被发送,另外的编码会被发送:
request.response().reset(8);
HTTP/2规范定义了可供使用的错误码。RequestHandler和responseHandler在流重置事件中,请求处理器将会被通知:
request.response().exceptionHandler(err -> {
if (errinstanceof StreamResetException) {
StreamResetException reset = (StreamResetException) err;
System.out.println("Stream reset " + reset.getCode());
}
});