微服务框架学习二:Http调用
1. HTTP接口的意义
二进制接口使用的是java/hessian序列化协议,不能很好的与其他语言通信,虽然hessian也是一种跨语言的通用协议,但很多语言没有很好的实现该协议的产品。
所以为了能够与其他语言进行服务通信,我们实现了http + json的协议实现,利用json原生的跨语言的特性。
2. 原理简图
描述:通过Netty暴露http服务端口,接收到http请求,通过HttpDecoder将其解析为HttpRequest,通过JSONDecoder提取service请求信息,生成Request请求对象,从而adapt到binary协议实现,交由request processor处理,返回Response结果,最终通过JSONEncoder编码为JSON格式数据,再通过HttpEncoder生成HttpResponse返回给Http接口调用方。
3. 协议格式
假定:有服务暴露接口ExampleService,服务名称:http://service.huifu.com/ExampleService/exampleService_1.0.0,定义了服务方法public String sayHello(String message),则HTTP访问协议描述如下:
请求协议:
Name | Value | Description | |
---|---|---|---|
URL | http://{machine-ip}:{http-port}/rpc.json | HTTP服务的访问地址,注意http端口号为pegasus端口号+1000,即:pegasus配置为8888,http端口就是9888 | |
Method | POST | 访问方式,推荐使用POST方式 | |
Encoding | UTF-8 | HTTP请求编码 | |
Params | _service |
http://service.huifu.com/ExampleService/exampleService_1.0.0 |
访问的服务名称 |
_method |
sayHello |
访问的服务接口方法名称 | |
_param | {"message" : "kitty"} |
传递到接口方法的参数值,使用json格式,形如:{"param1" : "value1", "param2" : {"f1" : 1, "f2" : "vvv"}},其中param1,param2为方法的参数名称,param1为string类型,param2为javabean类型,f1和f2为该javabean的属性名。 如:调用方法为sayHello(String message),则对应json为{"message":"kitty"}。如果调用方法为:sayHello(RequestDTO userDTO),RequestDTO中有一个属性为name,则对应的json为{"userDTO":{"name":"kitty"}}。 |
响应协议:
Name | Value | Description |
---|---|---|
格式 | {"type" : "xxx", "result" : "xxx", "error" : "xxx"} | HTTP服务接口的响应内容为JSON格式 |
type | "service" | "service-exception" | "exception" |
"service":业务处理正常返回 |
result | type = "service"时,服务方法的返回值,为JSON格式 |
若方法返回值为简单类型: |
error |
type = "service-exception" | "exception"时,返回的错误信息,为JSON格式 |
形如{"type" : "com.huifu.xx.BizException", "message" : "order_no is not supported"} |
关于服务方法参数名
默认情况下,pegasus通过asm读取服务实现类的方法签名信息,获取方法的参数名,但因重构或其他原因,该方法的参数名有可能被修改,从而导致原有的http接口使用方无法正常调用;
所以推荐在有可能提供http访问的服务方法上通过@Param注解定义参数名,这样就可以防止参数名被修改的情况,如void sayHello(@Param("message") String message),此时该方法就可以安全地重构为void sayHello(@Param("message") String msg),而不影响原有调用方;
注意:在使用的过程中发现,通过javassist获取参数名,如果使用javac编译器编译的class文件(maven默认使用),可能会出现无法读取参数名或读取错误; 我们遇到的几个问题case改用eclipse的ecj编译器后都可以fix,但我们无法去测试覆盖所有的代码case,因此若方法涉及到http调用时,请使用@Param的方式显式提供参数名;
btw: maven使用ecj作为编译器的详细配置如下 (1.0.2中已经使用asm替换javassist,该问题已FIXED)- 关于服务传输对象(DTO)的定义
由于使用json格式传递方法参数值,就牵扯到json ==> javabean的转换过程,而这个过程要求能明确地知道所有java对象及其属性的类型,所以在创建服务协议DTO对象时,如果这个对象牵扯到http方式的调用,那么就需要明确定义其类型,比如集合类型或数组,必须有明确的元素类型信息,所以Map, List, Set, Object[]都是无法转换的,必须是Map<String, String>, List<Order>, Set<Integer>, Order[]等有明确的元素类型声明的集合类和数组,即混合类型的集合http方式不支持;
由于json对象无法表示对象引用,所以在定义DTO时,应避免引用的方式,比如parent下定义了list<child>,child中又定义一个parent引用刚才的parent对象,这种方式不允许。
由于json对象的key一定是string类型,所以对于DTO中的Map,只能是Map<String, xx>, Map<Integer, xx>, Map<BigDecimal, xx>, Map<Boolean, xx>,Map<Date, xx>这样的Map类型,而Map<JavaBean, xx>这种类型则无法通过http接口调用,因为json无法表示这样的key。json转map:{"k1", "v1"} => map {"k1", "v1"}。
对于有Map<JavaBean, JavaBean>这种类型的dto,如果又需要通过http方式访问,那么请重构该map类型为List方式,比如List<MapBean>, MapBean中有JavaBean的key和JavaBean类型的value属性,即通过List<Entry>的方式实现Map,此时可以通过json表示,即[{"key1" : {xxx}, "value1" : {xxx}}, {"key2" : {xxx}, "value2" : {xxx}}]。 - 关于客户端调用
可以按照正常的http方式访问服务接口,由于目前各语言还没有自己封装的客户端,所以集群方面只能通过前端架设软负载的方式实现,后期考虑各语言封装自己的客户端,内部维护到各服务提供者的http长连接,并定期地通过服务注册中心的http接口更新服务提供者列表信息,搭配定期心跳探测移除不可用的连接,以便最终摒弃软负载。
通过http方式访问服务接口时,需要在客户端设置http请求的超时时间,以便在超过设定的超时时间后,客户端会立即抛出超时异常,并中断这次请求,否则会一直等待服务端返回,一旦服务端业务逻辑处理僵死,将无法返回http响应,并一直维持该http连接,造成资源无法释放;
微服务框架学习二:Http调用的更多相关文章
- kratos微服务框架学习笔记一(kratos-demo)
目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服务框架学习笔记一(kratos-demo) 今年大部分时间飘过去了,没怎么更博和githu ...
- [goa]golang微服务框架学习--安装使用
当项目逐渐变大之后,服务增多,开发人员增加,单纯的使用go来写服务会遇到风格不统一,开发效率上的问题. 之前研究go的微服务架构go-kit最让人头疼的就是定义服务之后,还要写很多重复的框架代码, ...
- [goa]golang微服务框架学习(二)-- 代码自动生成
之前用过go语言的反射来做一些代码生成,参考这篇. 但是这种方式,入侵太强,需要执行对应的申明调用, 所以对GOA框架的自动生成非常感兴趣,于是仔细研究了一下,发现用的比较巧妙, 这里先卖个关子,先看 ...
- [goa]golang微服务框架学习(三)-- 使用swagger-ui展示API
既然goa框架自动生成啦swagger-json文件,那么如何用swagger-ui展示出来呢? 这里分三步: 1.下载swagger-ui的web代码 2.添加swagger.json 和 swag ...
- Sping Cloud 微服务框架学习
Spring Cloud官方中文站 https://springcloud.cc
- .NET Core微服务架构学习与实践系列文章索引目录
一.为啥要总结和收集这个系列? 今年从原来的Team里面被抽出来加入了新的Team,开始做Java微服务的开发工作,接触了Spring Boot, Spring Cloud等技术栈,对微服务这种架构有 ...
- go微服务框架go-micro深度学习(四) rpc方法调用过程详解
上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取server的地 ...
- go微服务框架go-micro深度学习 rpc方法调用过程详解
摘要: 上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取serv ...
- go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用)
目录 go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用) warden direct demo-server gr ...
随机推荐
- 3D Computer Grapihcs Using OpenGL - 20 结合Buffer
在上一节的案例中,我们使用了四个Buffer Object,立方体的VertexBuffer,立方体的索引Buffer,四面体的VertexBuffer,四面体的索引Buffer. 我们这节尝试把两个 ...
- 如何下载如腾讯课堂等PC网页视频的方法
其实网上的教程有很多,实际也没那么复杂. 一.用插件法 方法是用插件,大多数主流的浏览器都是支持插件的,只要下载个插件应用市场的视频插件就可以搞定了. 当然,每个浏览器的视频插件品牌都是不一样的.这里 ...
- 图的普里姆(Prim)算法求最小生成树
关于图的最小生成树算法------普里姆算法 首先我们先初始化一张图: 设置两个数据结构来分别代表我们需要存储的数据: lowcost[i]:表示以i为终点的边的最小权值,当lowcost[i]=0说 ...
- 2018年5月6日GDCPC(广东赛区)总结
大二第二次参加省赛了,这次成绩不是太理想. ———————————————————————————————— day1:试机 约好的12点钟在地铁站集合,好像就我一个人迟到了5分钟,被sen主席批判一 ...
- python - 标准库:subprocess模块
subprocess的目的就是启动一个新的进程并且与之通信. subprocess模块中只定义了一个类: Popen. subprocess.Popen(args, bufsize=0, execut ...
- rocketMQ 通信协议格式
rocketMQ 使用 netty 通信,端对端的通信,为了避免粘包.分包,需要指定发送数据的边界. 使用的解码器是 LengthFieldBasedFrameDecoder // org.apach ...
- LoadRunner之检查点
一.什么是检查点 LoadRunner中检查点是用来判断脚本是否执行成功的.如果不加检查点,只要服务器返回的HTTP状态码是200,VuGen就认为脚本执行通过了.但是很多情况下服务器返回200并不代 ...
- sql 、linq、lambda 查询语句
http://www.cnblogs.com/lei2007/archive/2011/07/21/2113161.html
- 13 oracle数据库坏块-逻辑坏块(模拟/修复)
13 oracle数据库坏块-逻辑坏块 逻辑数据坏块的场景1)oracle bug也可能导致逻辑坏块的产生. 特别是parallel dml. 例如:Bug 5621677 Logical corru ...
- 转:【开源必备】常用git命令
原文:https://zhuanlan.zhihu.com/p/25868120 [开源必备]常用git命令 [已重置] 如今在技术领域,码农们习惯了开源,也离不开免费开源的代码,轻松获取代码,不 ...