dubbo http流量接入dubbo后端服务方式
作者:hello_zzw
Dubbo协议基于TCP,适用于后端高效RPC通信,但对前端不友好,可通过多协议发布或网关协议转换支持HTTP接入,主流网关如Higress、APISIX可实现协议转换和自动服务发现
简介
dubbo协议是基于TCP的二进制私有协议,更适合作为后端微服务间的高效RPC通信协议,也导致dubbo协议对于前端流量接入不是很友好。在dubo框架中,有两种方式可以解决这个问题:
- 多协议发布【推荐】,为dubbo协议服务暴露rest风格的http协议访问方式。
- 通过网关实现 http->dubbo协议转换,这种方式需要将http协议转换为后端服务能识别的dubbo协议,要求网关必须支持dubbo协议。
同时发布http、dubbo协议
dubbo框架支持为同一个服务发布多个协议,并且支持客户端通过同一个端口以不同的协议访问服务。
发布方式一
在dubbo协议的基础上增加tri协议
dubbo:
protocol:
name: dubbo
port: 20080
ext-protocol: tri
public interface DemoService01 {
String buyApple(Apple apple);
String sayHello(String name);
}
public class Apple implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public Apple(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
'}';
}
}
访问
curl --header "Content-Type:application/json" --data '{"name":"apple"}' http://localhost:20880/com.doudou.rpc.api.DemoService01/buyApple
curl --header "Content-Type:text/html" --data "name" http://localhost:20880/com.doudou.rpc.api.DemoService01/sayHello
发布方式二
只使用tri协议
dubbo:
protocol:
name: tri
port: 50053
访问
curl --header "Content-Type:application/json" --data '{"name":"apple"}' http://localhost:50053/com.doudou.rpc.api.DemoService01/buyApple
curl --header "Content-Type:text/html" --data "name" http://localhost:50053/com.doudou.rpc.api.DemoService01/sayHello
使用REST风格
引入javax.ws.rs-api
<dependency> <groupId>javax.ws.rs</groupId> <artifactId>javax.ws.rs-api</artifactId> <version>2.1.1</version> </dependency>
在使用方法上添加路径注解
import com.alibaba.fastjson2.JSON;
import com.doudou.demo.api.DemoService;
import com.doudou.demo.po.User;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
@Path("/demo")
@DubboService
public class DemoServiceImpl implements DemoService {
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
/**
* curl --header "Content-Type:text/html" --data "word" http://localhost:50051/demo/hello
* curl --header "Content-Type:text/html" --data "word" http://localhost:50051/com.doudou.demo.api.DemoService/sayHello
*/
@Path("/hello")
@POST
@Override
public String sayHello(String name) {
logger.info("name:{}", name);
return "hello " + name;
}
/**
* curl -X POST --header "Content-Type:text/html" http://localhost:50051/demo/hello2/world
*/
@Path("/hello2/{name}")
@POST
@Override
public String sayHello2(@PathParam("name") String name) {
logger.info("name 2:{}", name);
return "hello 2 " + name;
}
/**
* curl -X POST --header "Content-Type:application/json" "http://localhost:50051/demo/hello3?name=doudou"
*/
@Path("/hello3")
@POST
@Override
public String sayHello3(@QueryParam("name") String name) {
logger.info("name 3:{}", name);
return "hello 3 " + name;
}
/**
* curl -X POST "http://localhost:50051/demo/hello4" --header "Content-Type: application/x-www-form-urlencoded" -d "name=admin"
* curl -X POST "http://localhost:50051/com.doudou.demo.api.DemoService/sayHello4" --header "Content-Type: application/x-www-form-urlencoded" -d "name=admin1"
*
* @FormParam 用于接收表单数据(application/x-www-form-urlencoded 或 multipart/form-data):
*/
@Path("/hello4")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) // 必须指定表单类型
@Override
public String sayHello4(@FormParam("name") String name) {
logger.info("name 4:{}", name);
return "hello 4 " + name;
}
/**
* curl -X POST --header "Content-Type:application/json" -H "name: world" http://localhost:50051/demo/hello5
* curl -X POST --header "Content-Type:application/json" -H "name: world" http://localhost:50051/com.doudou.demo.api.DemoService/sayHello5
*/
@Path("/hello5")
@POST
@Override
public String sayHello5(@HeaderParam("name") String name) {
logger.info("name 5:{}", name);
return "hello 5 " + name;
}
/**
* curl -X POST --header "Content-Type:application/json" -H "cookie:name=world" http://localhost:50051/demo/hello6
* curl -X POST --header "Content-Type:application/json" -H "cookie:name=world" http://localhost:50051/com.doudou.demo.api.DemoService/sayHello6
*/
@Path("/hello6")
@POST
@Override
public String sayHello6(@CookieParam("name") String name) {
logger.info("name 6:{}", name);
return "hello 6 " + name;
}
/**
* curl -X POST --header "Content-Type:application/json" --data '{"id":1,"name":"world"}' http://localhost:50051/com.doudou.demo.api.DemoService/sayHello7
* curl -X POST --header "Content-Type:application/json" --data '{user:{"id":1,"name":"world"}, user2:{"id":2,"name":"world2"}}' http://localhost:50051/com.doudou.demo.api.DemoService/sayHello7
*
* {"id":1,"name":"world"}
*/
@Path("/hello7")
@POST
@Override
public String sayHello7(User user, User user2) {
logger.info("user:{}", JSON.toJSONString(user));
logger.info("user2:{}", JSON.toJSONString(user2));
return JSON.toJSONString(user);
}
}
使用网关转http协议为dubbo协议
网关需要实现的关键点:
协议转换,支持http到dubbo协议的转换,包括参数映射。自动地址发现,支持Nacos、Zookeeper、Kubernetes等主流注册中心,动态感知后端dubbo实例变化。结合dubbo协议的路由,如在发起 dubbo 协议调用时,支持按照特定规则地址筛选、传递附加参数到 dubbo 后端服务。
支持的开源网关
- Higress
- Apache APISIX
- Apache Shenyu
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
