常见的远程调用方式有以下几种:
RPC:Remote Produce Call远程过程调用,类似的还有RMI。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型
Http:http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议。也可以用来进行远程服务调用。缺点是消息封装臃肿。
现在热门的Rest风格,就可以通过http协议来实现。
RPC,即 Remote Procedure Call(远程过程调用),是一个计算机通信协议。 该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。说得通俗一点就是:A计算机提供一个服务,B计算机可以像调用本地服务那样调用A计算机的服务。
通过上面的概念,我们可以知道,实现RPC主要是做到两点:
RPC调用流程图:
想要了解详细的RPC实现,给大家推荐一篇文章:自己动手实现RPC
Http协议:超文本传输协议,是一种应用层协议。规定了网络传输的请求格式、响应格式、资源定位和操作的方式等。但是底层采用什么网络传输协议,并没有规定,不过现在都是采用TCP协议作为底层传输协议。说到这里,大家可能觉得,Http与RPC的远程调用非常像,都是按照某种规定好的数据格式进行网络通信,有请求,有响应。没错,在这点来看,两者非常相似,但是还是有一些细微差别。
例如我们通过浏览器访问网站,就是通过Http协议。只不过浏览器把请求封装,发起请求以及接收响应,解析响应的事情都帮我们做了。如果是不通过浏览器,那么这些事情都需要自己去完成。
既然两种方式都可以实现远程调用,我们该如何选择呢?
因此,两者都有不同的使用场景:
那么我们该怎么选择呢?
微服务,更加强调的是独立、自治、灵活。而RPC方式的限制较多,因此微服务框架中,一般都会采用基于Http的Rest风格服务。
既然微服务选择了Http,那么我们就需要考虑自己来实现对请求和响应的处理。不过开源世界已经有很多的http客户端工具,能够帮助我们做这些事情,例如:
HttpClient是Apache公司的产品,是Http Components下的一个组件。
官网地址:http://hc.apache.org/index.html
特点:
HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性;简化了很多操作。
简单而言HttpClient就是加强版的HttpURLConnection,但是HttpClient能够维护客户端和服务端的Session。
发起get请求:
@Test
public void testGet() throws IOException {
CloseableHttpClient httpClient;
/*初始化,相当于打开浏览器*/
httpClient= HttpClients.createDefault();
/*相当于在浏览器输入地址*/
HttpGet request = new HttpGet("http://www.baidu.com");
/*相当于在浏览器按下回车*/
String response = httpClient.execute(request, new BasicResponseHandler());
System.out.println(response);
}
发起Post请求:
package com.cpp.Http;
import com.alibaba.fastjson.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
public class HttpClientTest {
public static void main(String[] args) throws IOException {
HttpClientTest httpClientTest = new HttpClientTest();
httpClientTest.testGet();
}
public void testGet() throws IOException, JSONException {
/*初始化,相当于打开浏览器*/
CloseableHttpClient httpClient = HttpClients.createDefault();
/*相当于在浏览器输入地址*/
HttpGet request = new HttpGet("http://127.0.0.1/seeyon/rest/token/rest/rest");
/*相当于在浏览器按下回车*/
String response = httpClient.execute(request, new BasicResponseHandler());
// JSONArray jsonArray = new JSONArray(response);
JSONObject createJsonObject = JSON.parseObject(response);
String id = createJsonObject.getString("id");
String url = "http://127.0.0.1/seeyon/rest/thirdpartyPending/receive?token=" + id;
HttpPost httpPost = new HttpPost(url);
String str = "{
"\t\t\t\"title\": \"test",\n" +
"\t\t\t\"creationDate\": \"2020-05-20 12:40:49\",\n" +
"\t\t\t\"thirdReceiverId\": \"test\",\n" +
"\t\t\t\"senderName\": \"test\",\n" +
"\t\t\t\"thirdSenderId\": \"\",\n" +
"\t\t\t\"noneBindingSender\": \"test\",\n" +
"\t\t\t\"noneBindingReceiver\": \"test\",\n" +
"\t\t\t\"state\": \"0\",\n" +
"\t\t\t\"registerCode\": \"3001\",\n" +
"\t\t\t\"taskId\": \"1\"\n" +
"\t\t}";
String re = doPostJson(url, str);
System.out.println(re);
}
public static String doPostJson(String url, String json) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
HttpPost httpPost = new HttpPost(url);
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
}
如果想要得到对象,我们还需要手动进行Json反序列化,这一点比较麻烦。
HttpClient请求数据后是json字符串,需要我们自己把Json字符串反序列化为对象,我们会使用JacksonJson工具来实现。
JacksonJson是SpringMVC内置的json处理工具,其中有一个ObjectMapper类,可以方便的实现对json的处理:
// json处理工具
private ObjectMapper mapper = new ObjectMapper();
@Test
public void testJson() throws IOException {
Type type = new Type();
type.setId(1l);
List<Blog> blogs = new ArrayList<>();
Blog blog = new Blog();
blogs.add(blog);
type.setBlogs(blogs);
// 序列化
System.out.println("type = " + type);
String json = mapper.writeValueAsString(type);
System.out.println("json = " + json);
}
结果:
// json处理工具
private ObjectMapper mapper = new ObjectMapper();
@Test
public void testJson() throws IOException {
Type type = new Type();
type.setId(1l);
List<Blog> blogs = new ArrayList<>();
Blog blog = new Blog();
blogs.add(blog);
type.setBlogs(blogs);
// 序列化
System.out.println("type = " + type);
String json = mapper.writeValueAsString(type);
System.out.println("json = " + json);
// 反序列化,接收两个参数:json数据,反序列化的目标类字节码
Type result = mapper.readValue(json, Type.class);
System.out.println("result = " + result);
}
结果:
json转集合比较麻烦,因为你无法同时把集合的class和元素的class同时传递到一个参数。
因此Jackson做了一个类型工厂,用来解决这个问题:
// json处理工具
private ObjectMapper mapper = new ObjectMapper();
@Test
public void testJson() throws IOException {
Type type = new Type();
type.setId(1l);
List<Blog> blogs = new ArrayList<>();
Blog blog = new Blog();
blogs.add(blog);
type.setBlogs(blogs);
// 序列化,得到对象集合的json字符串
String json = mapper.writeValueAsString(Arrays.asList(type, type));
System.out.println("json=="+json);
// 反序列化,接收两个参数:json数据,反序列化的目标类字节码
List<Type> types = mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, Type.class));
for (Type u : types) {
System.out.println("u = " + u);
}
}
结果:
public static void main(String[] args) throws BusinessException {
String accessToken = "rRob1pQsag5U00";
String baseUrl = "https://app.ekuaibao.com/";
// String url = baseUrl + "api/openapi/v1/provisional/getProvisionalAuth?accessToken=" + accessToken;
String url = baseUrl + "api/openapi/v1/staffs/getStaffIds?accessToken=" + accessToken;
Map paramMap = new HashMap();
paramMap.put("type", "CODE");
String[] s = new String[1];
s[0] = "9014025295066775752";
paramMap.put("conditionIds", s);
String jsonString=JsonUtil.mapToJson(paramMap);
// String jsonString = JSON.toJSONString(paramMap);
System.out.println(jsonString);
String Result = HttpClientUtil.doPost(url, jsonString, "utf-8");
System.out.println(Result);
Map map=JsonUtil.jsonToMap(Result);
String items= (String) map.get("items");
items=items.substring(1, items.length()-1);
System.out.println(items);
Map item=JsonUtil.jsonToMap(items);
String uid = (String) item.get("id");
String userId = (String) item.get("userId");
String getUrl = "https://app.ekuaibao.com/api/openapi/v1/provisional/getProvisionalAuth?accessToken="
+ accessToken;
Map getUrlMap = new HashMap();
getUrlMap.put("uid", uid);
getUrlMap.put("userId", userId);
getUrlMap.put("pageType", "home");
getUrlMap.put("isApplet", true);
getUrlMap.put("expireDate", 120);
getUrlMap.put("overdueTokenRedirect", "[https://www.ekuaibao.com](https://www.ekuaibao.com)");
String getUrlJsonString = JsonUtil.mapToJson(getUrlMap);
String getUrlResult = HttpClientUtil.doPost(getUrl, getUrlJsonString, "utf-8");
Map getUrlResultMap = JsonUtil.jsonToMap(getUrlResult);
String ResultValue = (String) getUrlResultMap.get("value");
Map urlResult = JsonUtil.jsonToMap(ResultValue);
System.out.println("单点url==" + urlResult.get("message"));
}
需要的依赖:fastjson
<!--阿里 JSON,用于解析信息-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.57</version>
</dependency>
public static void main(String[] args) throws BusinessException {
String accessToken = "rRob1pQsag5U00";
String baseUrl = "https://app.ekuaibao.com/";
String url = baseUrl + "api/openapi/v1/staffs/getStaffIds?accessToken=" + accessToken;
Map paramMap = new HashMap();
paramMap.put("type", "CODE");
String[] s = new String[1];
s[0] = "9014025295066775752";
paramMap.put("conditionIds", s);
String jsonString = JSON.toJSONString(paramMap);
System.out.println(jsonString);
String Result = HttpClientUtil.doPost(url, jsonString, "utf-8");
System.out.println(Result);
JSONObject jsonObject = JSONObject.parseObject(Result);
JSONArray jsonArray = jsonObject.getJSONArray("items");
Iterator<Object> jsonIterator = jsonArray.iterator();
JSONObject parseObject = (JSONObject) jsonIterator.next();
String uid = parseObject.getString("id");
String userId = parseObject.getString("userId");
String getUrl = "https://app.ekuaibao.com/api/openapi/v1/provisional/getProvisionalAuth?accessToken="
+ accessToken;
Map getUrlMap = new HashMap();
getUrlMap.put("uid", uid);
getUrlMap.put("userId", userId);
getUrlMap.put("pageType", "home");
getUrlMap.put("isApplet", true);
getUrlMap.put("expireDate", 120);
getUrlMap.put("overdueTokenRedirect", "[https://www.ekuaibao.com](https://www.ekuaibao.com)");
String getUrlJsonString = JSON.toJSONString(getUrlMap);
String getUrlResult = HttpClientUtil.doPost(getUrl, getUrlJsonString, "utf-8");
Map getUrlResultMap = (Map) JSON.parse(getUrlResult);
Map ResultMapValue = (Map) getUrlResultMap.get("value");
String urlResult = ResultMapValue.get("message").toString();
System.out.println("单点url==" + urlResult);
}
OkHttpClient官网 OkHttp GitHub地址
导入依赖:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.6.0</version>
</dependency>
<!--JSON解析工具-->
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-parent</artifactId>
<version>2.8</version>
</dependency>
使用:
package com.cpp.Http;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
/**
* @author : cpp
* @create : 2020-05-23 - 13:23
* @describe:测试testOkHttpClient
*/
public class testOkHttpClient {
public static void main(String[] args) {
try {
/*向指定手机号发送短信*/
String result=run("http://neteasymusic.xiongsihao.com/captcha/sent?phone=137xxxxxxxx");
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
// Request是OkHttp中访问的请求,Builder是辅助类。Response即OkHttp中的响应。
private static String run(String url) throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
}
Request是OkHttp中访问的请求,Builder是辅助类。Response即OkHttp中的响应。
是Spring用于同步client端的核心类,简化了与http服务的通信,并满足RestFul原则,程序代码可以给它提供URL,并提取结果。默认情况下,RestTemplate默认依赖jdk的HTTP连接工具。
当然也可以 通过setRequestFactory属性切换到不同的HTTP源,比如Apache HttpComponents、Netty和OkHttp。
RestTemplate包含以下几个部分:
导入依赖:
<!--RestTemplate依赖在spring-web这个包下-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
使用:
package com.cpp.Http;
import org.springframework.web.client.RestTemplate;
/**
* @author : cpp
* @create : 2020-05-23 - 13:41
* @describe:
*/
public class testRestTemplate {
public static void main(String[] args) {
RestTemplate restTemplate=new RestTemplate();
//获取网易云热评http://neteasymusic.xiongsihao.com/song/url?id=1398663411
String result = restTemplate.getForObject("http://neteasymusic.xiongsihao.com/comment/hotwall/list",String.class);//调用的ul与返回类型
String result1 = restTemplate.getForObject("http://neteasymusic.xiongsihao.com/song/url?id=1398663411",String.class);//调用的ul与返回类型
System.out.println(result1);
}
}
评论