首页 > 其他分享 >手写基于 http 的RPC框架

手写基于 http 的RPC框架

时间:2022-10-25 13:02:46浏览次数:83  
标签:http 请求 RPC new rpc org import 手写 httpclient

一、模块划分

聚合工程

顶级模块:​new_rpc​

父模块:​httpclient_rpc​

子模块:​​httpclient_rpc_server、httpclient_rpc_client​、​httpclient_rpc_pojo​​

使用顶级模块是因为rpc协议自定义了两种方式,现在介绍的是​​httpclient_rpc​​这种方式

二、pom依赖

1.new_rpc

<groupId>com.zhkucst</groupId>
<artifactId>new_rpc</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>httpclient_rpc</module>
</modules>

2.httpclient_rpc

<parent>
<artifactId>new_rpc</artifactId>
<groupId>com.zhkucst</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>


<artifactId>httpclient_rpc</artifactId>
<packaging>pom</packaging>
<modules>
<module>httpclient_rpc_server</module>
<module>httpclient_rpc_client</module>
<module>httpclient_rpc_pojo</module>
</modules>

3.httpclient_rpc_pojo

<parent>
<artifactId>httpclient_rpc</artifactId>
<groupId>com.zhkucst</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>


<artifactId>httpclient_rpc_pojo</artifactId>

4.httpclient_rpc_server

<parent>
<artifactId>httpclient_rpc</artifactId>
<groupId>com.zhkucst</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>httpclient_rpc_server</artifactId>


<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.2.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>


<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.zhkucst</groupId>
<artifactId>httpclient_rpc_pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>

5.httpclient_rpc_client

<parent>
<artifactId>httpclient_rpc</artifactId>
<groupId>com.zhkucst</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>


<artifactId>httpclient_rpc_client</artifactId>


<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.2.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>


<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--httpclient 依赖-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.zhkucst</groupId>
<artifactId>httpclient_rpc_pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.1</version>
</dependency>
</dependencies>

三、内容

1.httpclient_rpc_pojo

pojo类

package com.zhkucst.httpclient.pojo;


import sun.security.jca.GetInstance;


import java.io.Serializable;
import java.util.Date;


/**
* @version v1.0
* @ClassName: User
* @Description: TODO
* @Author: fyp
* @data: 2021年 11月 07日 14:55
*/
public class User implements Serializable {


private String name;
private String password;
private Date birth;


public int getAge(){
if(birth == null){
return -1;
}
int birthYear = birth.getYear();
int currentYear = new Date().getYear();
return currentYear - birthYear;
}


public Date getBirth() {
return birth;
}


public void setBirth(Date birth) {
this.birth = birth;
}


public String getName() {
return name;
}


public void setName(String name) {
this.name = name;
}


public String getPassword() {
return password;
}


public void setPassword(String password) {
this.password = password;
}


@Override
public String toString() {
return "{\"name\":\""+ name +"\",\"password\":\""+ password +"\"}";
}
}

2.httpclient_rpc_server

服务端控制器,即客户端发起请求的控制区

package com.zhkucst.httpclientserver.controller;


import com.zhkucst.httpclient.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


import java.util.List;


/**
* @version v1.0
* @ClassName: TestController
* @Description: TODO
* @Author: fyp
* @data: 2021年 10月 18日 21:33
*/
@Controller
public class TestController {
/**
* CrossOrigin - 跨域请求注解。在响应头上增加跨域处理允许,可以让ajax跨越请求当前的服务方法
* @param users
* @return
*/
//使用请求体传递请求参数
@RequestMapping(value = "/bodyParams", produces = {"application/json;charset=UTF-8"})
@ResponseBody
@CrossOrigin
public String bodyParams(@RequestBody List<User> users){
System.out.println(users);
return users.toString();
}


@RequestMapping(value = "/params", produces = {"application/json;charset=UTF-8"})
@ResponseBody
public String params(String name, String password){
System.out.println("name - " + name + " ; password - " + password);
return "{\"msg\":\"登录成功\",\"user\":{\"name\":\""+name+"\",\"password\":\""+password+"\"}}";
}


@RequestMapping(value = "/test", produces = {"application/json;charset=UTF-8"})
@ResponseBody
public String test(){
return "{\"msg\":\"处理返回\"}";
}
}

3.httpclient_rpc_client

通过后端实现访问请求,后端以SpringBoot方式启动,前端直接java访问

package com.zhkucst.httpclient;


import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhkucst.httpclient.pojo.User;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;


import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;


/**
* @version v1.0
* @ClassName: TestHttpClient
* @Description: TODO
* @Author: fyp
* @data: 2021年 10月 18日 21:46
*/


public class TestHttpClient {
public static void main(String[] args) throws Exception{
//testGetNoParams();
//testGetParams();
testPost();
//testGetParams();
}


/**
* 有参Get请求
* @throws IOException
* @throws URISyntaxException
*/
public static void testGetParams() throws IOException, URISyntaxException {
//基于Builder构建请求地址
HttpClient client = HttpClients.createDefault();
URIBuilder builder = new URIBuilder("http://localhost/params");
//基于单参数传递,构建请求地址
//builder.addParameter("name", "bjsxt");
//builder.addParameter("password", "admin123");
//URI uri = builder.build();


//基于多参数传递,构建请求地址
List<NameValuePair> nvps = new ArrayList<>();
nvps.add(new BasicNameValuePair("name", "bjsxt"));
nvps.add(new BasicNameValuePair("password", "admin123"));
builder.addParameters(nvps);
URI uri = builder.build();


String result = EntityUtils.toString(client.execute(new HttpGet(uri)).getEntity());
System.out.println(result);


}


/**
* 无参数GET请求
* 使用浏览器,访问网站的过程是:
* 1、打开浏览器
* 2、输入网址
* 3、访问
* 4、看结果
* 使用HttpClient,访问WEB服务的过程:
* 1、创建客户端,相当于打开浏览器
* 2、创建请求地址,相当于输入地址
* 3、发起请求,相当于访问网站(回车键)
* 4、处理响应结果,相当于浏览器显示结果
*/
private static void testGetNoParams() throws IOException {
// 创建客户端对象
HttpClient client = HttpClients.createDefault();
// 创建请求地址
HttpGet get = new HttpGet("http://localhost:80/test");
// 发起请求,接收响应对象
HttpResponse response = client.execute(get);
// 获取响应体,响应数据是一个基于HTTP协议标准字符串封装的对象
HttpEntity entity = response.getEntity();
// 通过HTT实体工具类,转换响应体数据,使用的字符串是UTF-8
String responseString = EntityUtils.toString(entity, "UTF-8");


System.out.println("服务器响应的数据是 - [ " + responseString + "]");


client = null;
}


/**
* POST请求
*/
public static void testPost() throws Exception {
//无参数Post请求
HttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost("http://localhost/test");
HttpResponse response = client.execute(post);
System.out.println(EntityUtils.toString(response.getEntity(), "UTF-8"));


//有参数的Post请求
//请求头传递参数,和Get请求携带参数的方式一致
URIBuilder builder = new URIBuilder("http://localhost/params");
builder.addParameter("name", "post");
builder.addParameter("password", "postPassword");
URI uri = builder.build();
HttpResponse postResponse = client.execute(new HttpPost(uri));
System.out.println(EntityUtils.toString(postResponse.getEntity(), "UTF-8"));


//请求体传递参数
HttpPost bodyParamsPost = new HttpPost("http://localhost/bodyParams");
//定义请求体协议,设置请求参数。使用请求体传递参数的时候,需要定义请求体格式。默认是表单格式
//使用URLBuilder构建的URI对象,就是请求体传递参数的。
User u1 = new User();
u1.setName("zs");
u1.setPassword("123");
User u2 = new User();
u2.setName("ls");
u2.setPassword("456");


//手动json格式化
//String paramsString = "[" + u1.toString() + "," + u2.toString() + "]";


//使用jackson框架格式化
List<User> list = new ArrayList<>();
list.add(u1);
list.add(u2);
String paramsString;
ObjectMapper om = new ObjectMapper();
paramsString = om.writeValueAsString(list);


HttpEntity entity = new StringEntity(paramsString, "application/json", "UTF-8");
bodyParamsPost.setEntity(entity);
System.out.println(EntityUtils.toString(client.execute(bodyParamsPost).getEntity(), "UTF-8"));
String responseString = EntityUtils.toString(client.execute(bodyParamsPost).getEntity(), "UTF-8");
//将一个json格式的对象转换为java对象
String userString = responseString.substring(1, responseString.indexOf("},") + 1);
User responseUser = om.readValue(userString, User.class);
System.out.println(responseUser);
//将以json格式的对象数组转换为java对象数组
JavaType valueType = om.getTypeFactory().constructParametricType(List.class, User.class);
List<User> responseUserList = om.readValue(responseString, valueType);
System.out.println(responseUserList);


}

}

通过页面的​​ajax​​​请求访问,后端以​​springboot​​启动,前端以​web​​​启动

注意需要导入​​jquery.js​​包才可使用ajax请求,这里如果使用了跨域请求,也就是前后端分离请求,就需要在后端设置​​@CrossOrigin​​来允许跨域访问

手写基于 http 的RPC框架_spring

手写基于 http 的RPC框架_apache_02

后端没有设置​​@CrossOrigin​​会导致跨域请求而访问失败

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="jquery-3.5.1.min.js"></script>
<script type="text/javascript">
//javascript中默认的,ajax请求不能跨域
//跨域 - ajax所属的站点,和被请求的站点,不是同一个域
//域 - id,端口,域名,主机名,任何一个有变化,都是不同域
function sendBodyParams(){
$.ajax({
"url": "http://localhost:80/bodyParams",
"type": "post",
"data": "[{\"name\":\"abc\",\"password\":\"123\"},{\"name\":\"def\",\"password\":\"456\"}]",
"contentType": "application/json",//必须设定,代表请求体的格式。默认是text/plain,默认是参数名=参数值&参数名=参数值
"dataType": "json",
"success": function(data){
alert(data);
console.log(data);
}
});
}
</script>
</head>
<body style="text-align: center">
<button onclick="sendBodyParams()">测试ajax请求,请求体传递JSON数据</button>
</body>
</html>

标签:http,请求,RPC,new,rpc,org,import,手写,httpclient
From: https://blog.51cto.com/fyphome/5790973

相关文章

  • C#HTTP请求服务端客户端代码实现(转发)
    一、文件流方式(转自:http://blog.csdn.net/u011511086/article/details/53216330)///发送请求    ///</summary>    ///<paramname="url">请求地址</pa......
  • C#通用代理-http请求转发
    [HttpPost][HttpGet][Route("OaProxy/{*uri}")][DontWrapResult(WrapOnError=false,WrapOnSuccess=false,LogError=true)]publicasyncTaskOaProxy(stringu......
  • grpc-web使用
    一,proto协议编译js文件hello.proto文件1syntax="proto3";23packageapi;45//这里可以写服务注释6serviceHelloWorldService{7//这里可以......
  • Http状态码
    完整的HTTP1.1规范说明书来自于RFC2616,HTTP1.1的状态码被标记为新特性,因为许多浏览器只支持HTTP1.0。你应只把状态码发送给支持HTTP1.1的客户端,支持协议版本可以通过......
  • 使用docker部署nginx并配置https
     使用docker部署nginx并配置https 我只有一台服务器,但我想在这台服务器上运行多个项目,怎么办?总不能靠加端口区分吧?百度和Google是个好东西,于是我找到了答案,使用ng......
  • 银河麒麟安装nmon以及rpc.rstatd的方法
    银河麒麟安装nmon以及rpc.rstatd的方法 背景说明随着公司业务的发展,需要在ARM环境上面进行性能测试.为了进行ARM环境的验证,需要一些组件进行资料收集.比较好的......
  • http keepalive 和 tcp keepalive 的区别
    HTTPkeep-alive和TCPkeepalive的区别首先,二者是完全不同的东西:HTTPkeep-alive:是应用层(用户态)实现,称为HTTP长连接;TCPkeepalive,是传输层TCP(内核态)实现,称为TCP保活......
  • vscode 设置vue的用户片段-- vue文件 httpget httppost 请求 模板
      文件->首选项->用户片段{"生成vue模板":{"prefix":"vue","body":["<!--$1-->","<template>","<div......
  • HTTP协议
    1.名称HTTP协议-->超文本传输协议,英文-->HypertextTransferProtocol2.版本HTTP0.9、1.0、1.1、2,当前最广泛使用的是HTTP/1.1版本。3.特点HTTP协议最大的......
  • CPI 访问需验证的HTTP接口
    CPI访问外围系统接口时,有时需要先访问验证接口,获取AccessToken或得到账密,然后访问具体接口时,将获取到的验证结果传入具体接口进行访问1、OAuth2.0 AccessToken方式1.1、......