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