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

来源:互联网 发布:淘宝店铺店招设计 编辑:程序博客网 时间:2024/05/16 17:01

编写HTTP服务器与客户端

Vert.x使编写非阻塞的HTTP客户端和服务器更加容易。Vert.x支持HTTP/1.0,HTTP/1.1,HTTP/2等协议。HTTP基本的API与HTTP/1.x和HTTP/2是相同的,为了处理HTTP/2协义需要获取特殊的API。

创建HTTP服务器

使用默认的配置创建HTTP服务器是最简单的方法:

HttpServer server = vertx.createHttpServer();

配置HTTP服务器

如果不期望使用默认配置,可以在创建服务器时传入HttpServerOptions实例进行配置:

HttpServerOptions options = newHttpServerOptions().setMaxWebsocketFrameSize(1000000);

HttpServer server =vertx.createHttpServer(options);

配置HTTP/2服务器

·          在通过应用层协义协商(ALPN)的TLS协商时使用,h2用来标识HTTP/2协议

·          在TCP使用清晰文本,h2c标识HTTP/2协议,例如通过升级HTTP/1.1升级请求或直接建立的连接。

为了处理h2请求,TLS必须启用并同setUseAlpn一起用:

HttpServerOptions options = newHttpServerOptions()

   .setUseAlpn(true)

   .setSsl(true)

   .setKeyStoreOptions(newJksOptions().setPath("/path/to/my/keystore"));

HttpServer server = vertx.createHttpServer(options);

ALPN是TLS扩展,在客户端和服务器开始交互数据之前进行协议协商。不支持ALPN的客户端一直使用经典的SSL进行握手。如果服务器或客户端决定这样,ALPN一般同h2协议达成一致,尽管可以使用HTTP/1.1。

为了处理h2c请求,TLS必须被禁用,如果想升级到HTTP/2,服务器将HTTP/1.2请求升级到HTTP/2。这将直接接收以PRI *HTTP/2.0\r\nSM\r\n开头的h2c请求。

警示:大多数浏览器不支持h2c,所以对外服务的网站,应该用h2而不是h2c

在服务器接收一个http/2连接时,服务器将向客户端发送它的初始设置(initial settings).这些设置对怎样使用连接进行定义,默认的服务器初始设置如下:

·          getMaxConcurrentStreams: 100 作为HTTP/2推荐

·          其他默认的HTTP/2设置值

 

记录网络服务器行为

为了调试目的,可以记录网络行为

HttpServerOptions options = newHttpServerOptions().setLogActivity(true);

HttpServer server =vertx.createHttpServer(options)

参看记录网络行为章节获取详细说明。

开始服务器侦听

为了让服务器开始监听到来的请求,必需使用一个listen方法。为了告诉服务器在哪个网口那个端口侦听,可以使用配置选项。

HttpServer server = vertx.createHttpServer();

server.listen();

或者在调用listen方法时指定主机与端口,那么不配置时使用什么选项.

 HttpServer server = vertx.createHttpServer();

server.listen(8080, "myhost.com");

默认的主机是0.0.0.0,这意味着侦听所有可用的网址,默认端口为80. 因为实际绑定是异步的,所以在调用listen方法返回时可能并没有完成侦听。如果想获取服务器实际侦听完成的通知,可以在listen方法中添加一个处理器。下面是一个例子:

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!");

  }

});

获取进行请求的通知

在请求到达时需要设置请求处理器(requestHandler),获取通知:
HttpServer server = vertx.createHttpServer();

server.requestHandler(request -> {

  //Handle the request in here

});

处理请求

当一个请求到达,将会传一个HttpServerRequest的实例到请求处理器并调用请求处理器。这个对象代表了服务器端HTTP请求。在请求头全部被读取时,处理器会被调用。如果一个请求有请求体,这个请求体将会在请求处理器调用后某个进间到达服务器。

可以从服务器端请求对象中获取uri,path,params和头信息,和其他信息。每个服务器请求对象与一个服务响应对象关联。你使用response获取HttpServerResponse对象的引用。这里有一个服务器端处理请求并响应“hello world”到客端的例子。

vertx.createHttpServer().requestHandler(request-> {

 request.response().end("Hello world");

}).listen(8080);

请求版本

在HTTP请求中可以获取HTTP特定版本version

请求的方法

使用method获取请求中的方法(如是否是GET,POST,PUT,DELETE,HEAD,OPTIONS,etc)

请求URI

使用uri获取请求的URI.注意,这是一个实际传入HTTP请求的URI,并总是相对的URI。URI在HTTP规范-请求-URI节进行定义。

请求路径

使用 path可以获取URI中的path部分,

例如,如果请求的URI是:

a/b/c/page.html?param1=abc&param2=xyz

然后中径是

/a/b/c/page.html

请求查询

用query 返回URI中的query部分

如果请求的URI是:
a/b/c/page.html?param1=abc&param2=xyz

Query是:

param1=abc&param2=xyz

请求头

用header方法返回HTTP请求中的头。Header方法返回一个MultiMap实例,MultiMap类似通用的Map或者Hash,只是一个KEY可以有多个值,这是因为HTTP允许同一个头的KEY可以有多个值。Header的KEY大小写敏感:

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 sameresult:

System.out.println("User agent is " +headers.get("User-Agent"));

请求主机

用host方法获取请求的主机。对于HTTP/1.x 请求中的host头被返回,对HTTP/1请求:authority的假头被返回。

请求参数

用params返回请求中的参数。与headers返回的MultiMap实例类似,因为一个名称可以参数可以有多个值。请求参数通过请求URI发送给服务器,紧随路径。例如:

/page.html?param1=abc&param2=xyz

包含的参数如下:

param1: 'abc'

param2: 'xyz

请求参数可以从请求的URL中获取。如果有表单属性作为HTML表单任务提交到multi-part/form-data请求,而这些属性将不会出现在params中。

远程地址

请求发送者的地址,通过remoteAddress获取。

绝对URI

传入到HTTP请求中的URI一般是相对地址。如果你想获取响应的绝对URI,使用absoluteURI.

结束处理器

在整个请求包括请求体被完全读取,endHandler将被调用。

从请求体中读取数据

一般情况下HTTP请包含我们需要读取的请求体。如前所述,在请求头到达时,请处理器被调用,所以在那个点请求对象并不包含请求体。

这是因为请求体可能比较大(如文件上传),通常我们在处理前并不想在内存缓存整个请求体,如果那样,服务器内存资源可以会被耗尽。

为了获取体,可以在请求上添加处理器,这样每当有请求体的数据块到达时,处理器就会被调用。下面是一个例子:
request.handler(buffer -> {

 System.out.println("I have received a chunk of the body of length" + buffer.length());

});

传给处理器的参数是Buffer,处理可以被多次调用,这取决于请求体的大小。

一些情况下(请求体很小),可以将集所有的请求体缓存在内存中,所以可象下面一样组合:

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());

});

这是一个常用的例子,Vert.x提供了一个bodyHandler为你处理。在所有请求体到达后,请求体处理器执行一次。

request.bodyHandler(totalBuffer -> {

 System.out.println("Full body received, length = " +totalBuffer.length());

});

 

泵接请求

 

请求对象是一个读数据流(ReadStream),所以可以将期泵接到写数据流实例 (WriteStream).参看流与泵章节获取详细说明。

处理HTML表单

HTML表达可使用application/x-www-form-rlencoded 或者 multipart/form-data的内空类别进行提交。

对于URL编码的表单,表单的属性会编码进URL,与查询参数类似。

对于多部分表单,表单属性被编码时请求体,直到所有的请求体被从线上读取,才能得到。

多部分表单可以包含文件上传。

如果你想获取多部分表单的属性,在任何请求体被读取前,应该告知Vert.x期望收到这样的表单,通过设置setExpectMultipart为true设置告知,然就可以在整个请求体读取完成后,通过formAttributes获取表单的实际属性。

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();

  });

});

处理表单上传文件

Vert.x通过编码进行multi-part请求体,进行文件上传。为了获取上传文件,必须设置Vert.x获取multi-part表单并在请设置uploadHandler处理上传文件。上传处理器在每个上传对象到达服务器时被调用。HttpServerFileUpload实例作为上传处理器参数。

server.requestHandler(request -> {

 request.setExpectMultipart(true);

 request.uploadHandler(upload -> {

   System.out.println("Got a file upload " + upload.name());

  });

});

文件上传可以大到我们不能在一个缓存中提供整个上传实体,如果缓存整个上传实体可能会耗尽服务器内存,所以以数据块的方式接收上传数据。

request.uploadHandler(upload -> {

 upload.handler(chunk -> {

   System.out.println("Received a chunk of the upload of length "+ chunk.length());

  });

});

上传对象是一个读取流,所以可以泵接请求体到任意的写数据流实例。参看流和泵接章节获取详细说明。

如果想上传文件到磁盘的某个地方,请使用streamToFileSystem:

request.uploadHandler(upload -> {

 upload.streamToFileSystem("myuploads_directory/" +upload.filename());

});

警示:在生产系统中必须确定检查文件名,避免恶意客户端上传文件到你的文件系统的任意地方,参看安全注释获取更多信息。
0 0
原创粉丝点击