Vert.x(vertx)发送 HTTP/HTTPS请求
Vert.x Web服务有两种协议,一种是HTTP,另外一种是使用ssl的HTTPS,请求的方式有五种,分别是get、post、put、delete、head。为了简单,服务端主要实现对HTTP协议的get和post的请求处理。如下
1 @Override 2 public void start() throws Exception { 3 4 HttpServer server = vertx.createHttpServer(); 5 Router router = Router.router(vertx); 6 7 // 处理get请求 8 router.get("/get").handler(request -> { 9 String username = request.request().getParam("username"); 10 String password = request.request().getParam("password"); 11 12 System.out.println(username + " " + password); 13 14 request.response().end("get request success"); 15 }); 16 17 // 处理post请求 18 router.post("/post").handler(request -> { 19 request.request().bodyHandler(body->{ 20 System.out.println(body.toJsonObject().toString()); 21 JsonObject responseData = new JsonObject() 22 .put("msg","success"); 23 request.response().end(responseData.toString()); 24 }); 25 }); 26 27 server.requestHandler(router::accept); 28 server.listen(80); 29 30 }
上面的代码就是创建了一个Web服务,监听/get和/post地址,分别处理get请求和post请求。如果对上面的代码不理解的朋友可以参考《创建HTTP服务》 和 《Web开发 - 路由》
发送HTTP GET请求
GET请求对于一些敏感信息非常容易泄露。
1 @Override 2 public void start() throws Exception { 3 // 创建WebClient,用于发送HTTP或者HTTPS请求 4 WebClient webClient = WebClient.create(vertx); 5 // 以get方式请求远程地址 6 webClient.getAbs("http://localhost/get").send(handle -> { 7 // 处理响应的结果 8 if (handle.succeeded()) { 9 // 这里拿到的结果就是一个HTML文本,直接打印出来 10 System.out.println(handle.result().bodyAsString()); 11 } 12 }); 13 }
这是最简单的一种请求方式,在上面的代码中,首先创建了WebClient对象,通过WebClient可以方便的发送HTTP请求。有朋友可能会注意到,在Vert.x提供的核心包中有HttpClient,可以通过Vert.x实例获取
HttpClient httpClient = vertx.createHttpClient();
HTTPClient这个接口也可以发送HTTP请求,只是它比较低级,如果在请求中带复杂数据,附带请求头,封装响应结果都需要自己来处理。因此,Vert.x提供了vertx-web-client的支持。
WebClient的API非常简单,发送GET请求,可以使用getAbs。Abs是绝对地址的意思,除了使用绝对地址,还可以使用域名+端口号+请求地址的方式,代码如下:
1 webClient.get(80, "localhost", "/get").send(handle -> { 2 // 处理响应的结果 3 if (handle.succeeded()) { 4 // 这里拿到的结果就是一个HTML文本,直接打印出来 5 System.out.println(handle.result().bodyAsString()); 6 } 7 });
第一个参数是端口号,第二个参数是域名,第三个参数是请求地址。
发送HTTP请求 请求头
HTTP协议包含三部分,请求行、请求头和请求体。一般来讲,不建议在GET请求的请求体中带数据,但请求头数据是每个请求都有的,比如使用User-Agent指定设备的类型以及操作系统等等。我们在请求远程服务的时候,如何设置请求头呢,代码如下
1 webClient.get(80, "localhost", "/get") 2 .putHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0") 3 .send(handle -> { 4 // 处理响应的结果 5 if (handle.succeeded()) { 6 // 这里拿到的结果就是一个HTML文本,直接打印出来 7 System.out.println(handle.result().bodyAsString()); 8 } 9 });
设置超时时间
HTTP请求是一个耗时操作,受到网络等因素的影响,很多时候我们要限制一个最大的请求时间,超过这个时间就不去处理了,可以通过WebClientOptions设置
1 @Override 2 public void start() throws Exception { 3 // 创建WebClient,用于发送HTTP或者HTTPS请求 4 WebClientOptions webClientOptions = new WebClientOptions() 5 .setConnectTimeout(500); // ms 6 WebClient webClient = WebClient.create(vertx, webClientOptions); 7 // 以get方式请求远程地址 8 webClient.getAbs("http://localhost/get").send(handle -> { 9 // 处理响应的结果 10 if (handle.succeeded()) { 11 // 这里拿到的结果就是一个HTML文本,直接打印出来 12 System.out.println(handle.result().bodyAsString()); 13 } 14 }); 15 }
除了设置超时时间以外,还可以设置是否重定向到页面以及HTTPS的证书等等。
发送HTTP GET请求 带数据
很多的情况下在请求服务端的时候都需要带一些必要的数据,GET请求带数据有两种方式,第一种就是在请求的URL后直接拼接参数 ?username=xxx&password=xxx的形式。还有一种方式是通过addQueryParam的方式添加请求参数,如下所示
1 @Override 2 public void start() throws Exception { 3 // 创建WebClient,用于发送HTTP或者HTTPS请求 4 WebClient webClient = WebClient.create(vertx); 5 // 以get方式请求远程地址 6 webClient 7 .getAbs("http://localhost/get") 8 // 通过这种方式发送数据 9 .addQueryParam("username", "admin") 10 .addQueryParam("password", "admin123") 11 .send(handle -> { 12 // 处理响应的结果 13 if (handle.succeeded()) { 14 // 这里拿到的结果就是一个HTML文本,直接打印出来 15 System.out.println(handle.result().bodyAsString()); 16 } 17 }); 18 }
上面的代码就是向服务端发送两个参数,一个是username一个是password。这两个参数在网络上都是通过明文进行传输的,因此如果真的是要做登陆,一定不要使用get方式。这里我们并不需要去思考服务端如何接收这两个参数,客户端只要能够保证参数能够发送出去就可以了。
发送POST请求
GET方式在浏览器中使用的还是比较多,但在服务调用中一般比较少,在服务调用中一般会选择使用POST方式,下面看POST方式请求远程服务的案例,代码如下
1 @Override 2 public void start() throws Exception { 3 // 创建WebClient,用于发送HTTP或者HTTPS请求 4 WebClient webClient = WebClient.create(vertx); 5 // 以get方式请求远程地址 6 webClient.postAbs("http://localhost/post") 7 .send(handle -> { 8 // 处理响应的结果 9 if (handle.succeeded()) { 10 // 这里拿到的结果就是一个HTML文本,直接打印出来 11 System.out.println(handle.result().bodyAsString()); 12 } 13 }); 14 }
POST方式和GET方式请求在API调用上非常类似,上面的代码中,只是调用了postAbs方法而已,底层通信协议是如何封装的开发者完全不用关注,getAbs和postAbs在底层处理方式是完全不同的。
发送POST请求 带数据
当然了,一般进行服务调用的时候也都需要附带一些数据,比如我们要调用发短信服务,那么就至少需要附带手机号和短信内容过去当然还需要一些认证信息,服务提供方发送短信成功之后需要告诉我们已经受理成功,或者仅仅是收到我们的请求。在POST中带数据的方式比较多,数据类型也多样化,主要有以下三种类型
1. form表单
2. json字符串
3. xml字符串
第一种数据类型是前后端交互时经常使用的方式,第二、三种方式是服务调用常用的序列化方式。下面以发送JSON字符串的形式来调用远程服务,代码如下:
1 @Override 2 public void start() throws Exception { 3 // 创建WebClient,用于发送HTTP或者HTTPS请求 4 WebClient webClient = WebClient.create(vertx); 5 6 // 构造请求的数据 7 JsonObject data = new JsonObject() 8 .put("username", "admin") 9 .put("password", "admin123"); 10 11 // 以get方式请求远程地址 12 webClient.postAbs("http://localhost/post") 13 .sendJsonObject(data, handle -> { 14 // 处理响应的结果 15 if (handle.succeeded()) { 16 // 这里拿到的结果就是一个HTML文本,直接打印出来 17 // handle.result().bodyAsJsonObject() 可以解析Json数据 18 System.out.println(handle.result().bodyAsString()); 19 } 20 }); 21 }
在上面的代码中,我们先创建了一个JsonObject对象,和GSON和fastjson中的JsonObject类似,但感觉Vert.x提供的JsonObject更为强大一些,通过JsonObject可以非常方便的构造一个Json字符串。当然除了JsonObject以外,Vert.x还提供了JsonArray可以构造一个json数组。
构造一个json对象以后,在请求远程服务的时候可以通过sendJsonObject方法,将构造好的json对象传入,Vert.x底层就会给我们把json对象格式化为json字符串,发送给服务提供者。服务提供者就会收到如下请求数据:
1 { 2 "username": "admin", 3 "password": "admin123" 4 }
服务端收到这些数据也可以使用JsonObject对象将字符串转为json对象,方便的读写数据。当然了,服务端收到我们的数据之后进行处理,最后还需要给客户端响应数据,服务端也可以给客户端响应json字符串,客户端同样可以对json字符串进行处理。
这种案例非常多,可以参考微信支付扫码接口文档
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
请求HTTPS服务
使用HTTP协议,不管是get请求还是post请求,数据传输都是明文传输的,因此敏感信息通过HTTP方式都有暴露的危险。现在越来越多的网站都已经升级为HTTPS协议,通过加密的方式进行传输,保证敏感信息的安全。
HTTP请求安全简单来讲有两点,第一个是数据被篡改,第二个是敏感数据被窃取。解决数据篡改的手段是对消息进行签名,解决数据窃取的手段是加密,HTTPS实际上就是为了解决敏感信息被窃取的问题的。
对于HTTPS的原理这里不做过多的介绍,感兴趣的朋友可以在网络上搜索相关文章,在Vert.x中请求HTTPS也非常简单,代码如下:
1 @Override 2 public void start() throws Exception { 3 // 创建WebClient,用于发送HTTP或者HTTPS请求 4 WebClient webClient = WebClient.create(vertx); 5 // 以get方式请求远程地址 6 webClient.getAbs("https://www.sina.com") 7 .ssl(true) 8 .send(handle -> { 9 // 处理响应的结果 10 if (handle.succeeded()) { 11 // 这里拿到的结果就是一个HTML文本,直接打印出来 12 System.out.println(handle.result().bodyAsString()); 13 } 14 }); 15 }
上面的代码是我要请求新浪的主页,可以看到,只需要在调用send方法之前,调用ssl方法,并指定为true即可。