Vert.x 内核模块 编写HTTP服务器(七【2】)

来源:互联网 发布:张北榕泰大数据项目 编辑:程序博客网 时间:2024/05/28 18:44

获取定制的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());

  }

});

0 0