从 Dubbo 3.3 版本开始,Triple 协议重用已有的 HTTP 协议栈,实现了全面的 REST 风格服务导出能力。无需使用泛化或网关层协议转换,无需配置,用户即可通过 HTTP 协议去中心化直接访问后端的 Triple 协议服务。同时,针对高级 REST 用法,如路径定制、输出格式定制和异常处理,提供了丰富的注解和 SPI 扩展支持。其主要特性包括:
让我们从一个简单的例子开始了解 Triple Rest。您可以直接下载已有的示例项目以快速上手,假设您已经安装好 Java、Maven 和 Git
# 获取示例代码
git clone --depth=1 https://github.com/apache/dubbo-samples.git
cd dubbo-samples/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic
# 直接运行
mvn spring-boot:run
# 或打包后运行
mvn clean package -DskipTests
java -jar target/dubbo-samples-triple-rest-basic-1.0.0-SNAPSHOT.jar
当然,也可以直接用IDE导入工程后直接执行
org.apache.dubbo.rest.demo.BasicRestApplication#main
来运行,并通过下断点 debug 的方式来深入理解原理。
// 服务接口
package org.apache.dubbo.rest.demo;
import org.apache.dubbo.remoting.http12.rest.Mapping;
import org.apache.dubbo.remoting.http12.rest.Param;
public interface DemoService {
String hello(String name);
@Mapping(path = "/hi", method = HttpMethods.POST)
String hello(User user, @Param(value = "c", type = ParamType.Header) int count);
}
// 服务实现
@DubboService
public class DemoServiceImpl implements DemoService {
@Override
public String hello(String name) {
return "Hello " + name;
}
@Override
public String hello(User user, int count) {
return "Hello " + user.getTitle() + ". " + user.getName() + ", " + count;
}
}
// 模型
@Data
public class User {
private String title;
private String name;
}
curl -v "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hello?name=world"
# 输出如下
#> GET /org.apache.dubbo.rest.demo.DemoService/hello?name=world HTTP/1.1
#> Host: 127.0.0.1:8081
#> User-Agent: curl/8.7.1
#> Accept: */*
#>
#* Request completely sent off
#< HTTP/1.1 200 OK
#< content-type: application/json
#< alt-svc: h2=":8081"
#< content-length: 13
#<
#"Hello world"
代码讲解:
可以看到输出了 “Hello world” ,有双引号是因为默认输出 content-type 为 application/json
通过这个例子可以了解 Triple 默认将服务导出到
/{serviceInterface}/{methodName}
路径,并支持通过url方式传递参数
curl -v -H "c: 3" -d 'name=Yang' "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr"
# 输出如下
#> POST /org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr HTTP/1.1
#> Host: 127.0.0.1:8081
#> User-Agent: curl/8.7.1
#> Accept: */*
#> c: 3
#> Content-Length: 9
#> Content-Type: application/x-www-form-urlencoded
#>
#* upload completely sent off: 9 bytes
#< HTTP/1.1 200 OK
#< content-type: text/plain
#< alt-svc: h2=":8081"
#< content-length: 17
#<
#Hello Mr. Yang, 3
代码讲解:
可以看到输出 Hello Mr. Yang, 3 ,没有双引号是因为通过指定后缀 txt 的方式要求用 text/plain
输出
通过这个例子可以了解如何通过 Mapping 注解来定制路径,通过 Param
注解来定制参数来源,并支持通过 post body 或
url方式传递参数,详细说明参见: Basic使用指南
可以通过打开 debug 日志的方式来了解rest的启动和响应请求过程
logging:
level:
"org.apache.dubbo.rpc.protocol.tri": debug
"org.apache.dubbo.remoting": debug
打开后可以观察到 Rest 映射注册和请求响应过程
# 注册mapping
DEBUG o.a.d.r.p.t.TripleProtocol : [DUBBO] Register triple grpc mapping: 'org.apache.dubbo.rest.demo.DemoService' -> invoker[tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService]
INFO .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] BasicRequestMappingResolver resolving rest mappings for ServiceMeta{interface=org.apache.dubbo.rest.demo.DemoService, service=DemoServiceImpl@2a8f6e6} at url [tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService]
DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Register rest mapping: '/org.apache.dubbo.rest.demo.DemoService/hi' -> mapping=RequestMapping{name='DemoServiceImpl#hello', path=PathCondition{paths=[org.apache.dubbo.rest.demo.DemoService/hi]}, methods=MethodsCondition{methods=[POST]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(User, int), service=DemoServiceImpl@2a8f6e6}
DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Register rest mapping: '/org.apache.dubbo.rest.demo.DemoService/hello' -> mapping=RequestMapping{name='DemoServiceImpl#hello~S', path=PathCondition{paths=[org.apache.dubbo.rest.demo.DemoService/hello]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(String), service=DemoServiceImpl@2a8f6e6}
INFO .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Registered 2 REST mappings for service [DemoServiceImpl@44627686] at url [tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] in 11ms
# 请求响应
DEBUG .a.d.r.p.t.r.m.RestRequestHandlerMapping : [DUBBO] Received http request: DefaultHttpRequest{method='POST', uri='/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr', contentType='application/x-www-form-urlencoded'}
DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Matched rest mapping=RequestMapping{name='DemoServiceImpl#hello', path=PathCondition{paths=[/org.apache.dubbo.rest.demo.DemoService/hi]}, methods=MethodsCondition{methods=[POST]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(User, int), service=DemoServiceImpl@2a8f6e6}
DEBUG .a.d.r.p.t.r.m.RestRequestHandlerMapping : [DUBBO] Content-type negotiate result: request='application/x-www-form-urlencoded', response='text/plain'
DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response body is: '"Hello Mr. Yang, 3"'
DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response headers sent: {:status=[200], content-type=[text/plain], alt-svc=[h2=":8081"], content-length=[17]}
兼容 SpringMVC 和 JAX-RS 的映射方式,相关文档:
还支持通过实现 SPI org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver
来自定义路径映射
books
字符串常量,最基本的类型,匹配一个固定的段?
匹配一个字符*
匹配路径段中的零个或多个字符**
匹配直到路径末尾的零个或多个路径段{spring}
匹配一个路径段并将其捕获为名为 “spring” 的变量{spring:[a-z]+}
使用正则表达式 [a-z]+
匹配路径段,并将其捕获为名为 “spring” 的路径变量{*spring}
匹配直到路径末尾的零个或多个路径段,并将其捕获为名为 “spring” 的变量,如果写 {*}
表示不捕获
/pages/t?st.html
— 匹配 /pages/test.html
以及 /pages/tXst.html
,但不匹配 /pages/toast.html
/resources/*.png
— 匹配 resources
目录中的所有 .png
文件com/**/test.jsp
— 匹配 com
路径下的所有 test.jsp
文件org/springframework/**/*.jsp
— 匹配 org/springframework
路径下的所有 .jsp
文件/resources/**
— 匹配 /resources/
路径下的所有文件,包括 /resources/image.png
和 /resources/css/spring.css
/resources/{*path}
— 匹配 /resources/
下的所有文件,以及 /resources
,并将其相对路径捕获在名为 “path” 的变量中;例如,
/resources/image.png
会匹配到 “path” → “/image.png”,/resources/css/spring.css
会匹配到 “path” → “/css/spring.css”/resources/{filename:\\w+}.dat
— 匹配 /resources/spring.dat
并将值 “spring” 分配给 filename
变量/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}
— 匹配 /example-2.1.5.html
则 name
为 example
,
version
为 2.1.5
,ext
为 .html
小技巧如果使用正则不希望跨段可以使用 {name:[^/]+}
来匹配
具体的匹配处理代码:DefaultRequestMappingRegistry.java RequestMapping.java
PathUtils.normalize
对路径进行清洗,去掉诸如 /one/../
/one/./
之类间接路径,保证一定已 /
开头http method
是否匹配path
是否匹配paramter
是否匹配(JAX-RS不支持)header
是否匹配content-type
是否匹配(Consumes)accept
是否匹配 (Produces)serviceGroup
和 serviceVersion
是否匹配method
首字母签名是否匹配/
匹配开启并且路径 /
结尾则去掉尾 /
尝试从第2步开始匹配~
表示开启 method 首字母签名匹配,尝试从第2步开始匹配与 Spring 不同,Spring 在路径完全相同时会直接报错并阻止启动,而 Triple Rest 具备开箱即用的特性,为了避免影响现有服务,默认只会打印 WARN 日志。在运行时,如果最终无法确定最高优先级的映射,才会抛出错误。
不同方言支持的入参类型不同,详情请参见各方言使用指南。
还支持通过实现 SPI
org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver
来自定义入参解析
名称 | 说明 | Basic 注解 | SpringMVC注解 | JAX-RS注解 | 数组或集合处理方式 | Map处理方式 |
---|---|---|---|---|---|---|
Param | Query或Form的参数 | @Param | @RequestParam | - | 多值 | 所有参数的Map |
Query | url上带的参数 | - | - | @QueryParam | 多值 | 所有Query参数的Map |
Form | form表单带的参数 | - | - | @FormParam | 多值 | 所有Form参数的Map |
Header | HTTP头 | @Param(type=Header) | @RequestHeader | @HeaderParam | 多值 | 所有Header参数的Map |
Cookie | Cookie值 | @Param(type=Cookie) | @CookieValue | @CookieParam | 多值 | 所有Cookie参数的Map |
Attribute | Request属性 | @Param(type=Attribute) | @RequestAttribute | - | 多值 | 所有Attribute的Map |
Part | Multipart文件 | @Param(type=Part) | @RequestHeader | @HeaderParam | 多值 | 所有Part的Map |
Body | 请求body | @Param(type=Body) | @RequestBody | @Body | 尝试解析为数组或集合 | 尝试解析为目标类型 |
PathVariable | path变量 | @Param(type=PathVariable) | @PathVariable | @PathParam | 单值数组或集合 | 单值Map |
MatrixVariable | matrix变量 | @Param(type=MatrixVariable) | @MatrixVariable | @MatrixParam | 多值 | 单值Map |
Bean | java bean | 无需注解 | @ModelAttribute | @BeanParam | 尝试解析为Bean数组或集合 | - |
类型 | 说明 | 激活条件 |
---|---|---|
org.apache.dubbo.remoting.http12.HttpRequest | HttpRequest对象 | 默认激活 |
org.apache.dubbo.remoting.http12.HttpResponse | HttpResponse对象 | 默认激活 |
org.apache.dubbo.remoting.http12.HttpMethods | 请求Http方法 | 默认激活 |
java.util.Locale | 请求Locale | 默认激活 |
java.io.InputStream | 请求输入流 | 默认激活 |
java.io.OutputStream | 响应输出流 | 默认激活 |
javax.servlet.http.HttpServletRequest | Servlet HttpRequest对象 | 引入Servlet API jar |
javax.servlet.http.HttpServletResponse | Servlet HttpResponse对象 | 同上 |
javax.servlet.http.HttpSession | Servlet HttpSession对象 | 同上 |
javax.servlet.http.Cookie | Servlet Cookie对象 | 同上 |
java.io.Reader | Servlet Request Reader对象 | 同上 |
java.io.Writer | Servlet Response Writer对象 | 同上 |
可通过 RpcContext
来获取
// Dubbo http req/resp
HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class);
HttpResponse response = RpcContext.getServiceContext().getRequest(HttpResponse.class);
// Servlet http req/resp
HttpServletRequest request = RpcContext.getServiceContext().getRequest(HttpServletRequest.class);
HttpServletResponse response = RpcContext.getServiceContext().getRequest(HttpServletResponse.class);
拿到request之后,通过 attribute 可以访问一些内置属性,参见:RestConstants.java
默认支持大部分从 String 到目标类型的参数类型转换,主要包括以下几大类:
同时也完整支持泛型类型,包括复杂嵌套,具体地实现代码参见: GeneralTypeConverter.java
还支持通过实现SPI
org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter
来自定义参数类型转换
Source Type | Target Type | Description | Default Value |
---|---|---|---|
String | double | Converts to a double | 0.0d |
String | float | Converts to a float | 0.0f |
String | long | Converts to a long | 0L |
String | int | Converts to an integer | 0 |
String | short | Converts to a short | 0 |
String | char | Converts to a character | 0 |
String | byte | Converts to a byte | 0 |
String | boolean | Converts to a boolean | false |
String | BigInteger | Converts to a BigInteger | null |
String | BigDecimal | Converts to a BigDecimal | null |
String | Date | Converts to a Date | null |
String | Calendar | Converts to a Calendar | null |
String | Timestamp | Converts to a Timestamp | null |
String | Instant | Converts to an Instant | null |
String | ZonedDateTime | Converts to a ZonedDateTime | null |
String | LocalDate | Converts to a LocalDate | null |
String | LocalTime | Converts to a LocalTime | null |
String | LocalDateTime | Converts to a LocalDateTime | null |
String | ZoneId | Converts to a ZoneId | null |
String | TimeZone | Converts to a TimeZone | null |
String | File | Converts to a File | null |
String | Path | Converts to a Path | null |
String | Charset | Converts to a Charset | null |
String | InetAddress | Converts to an InetAddress | null |
String | URI | Converts to a URI | null |
String | URL | Converts to a URL | null |
String | UUID | Converts to a UUID | null |
String | Locale | Converts to a Locale | null |
String | Currency | Converts to a Currency | null |
String | Pattern | Converts to a Pattern | null |
String | Class | Converts to a Class | null |
String | byte[] | Converts to a byte array | null |
String | char[] | Converts to a char array | null |
String | OptionalInt | Converts to an OptionalInt | null |
String | OptionalLong | Converts to an OptionalLong | null |
String | OptionalDouble | Converts to an OptionalDouble | null |
String | Enum class | Enum.valueOf | null |
String | Array or Collection | Split by comma | null |
String | Specified class | Try JSON String to Object | null |
String | Specified class | Try construct with single String | null |
String | Specified class | Try call static method valueOf | null |
默认支持以下 Content-Type,提供相应的编码和解码功能。
还支持通过实现SPI
org.apache.dubbo.remoting.http12.message.(HttpMessageDecoderFactory|HttpMessageEncoderFactory)
来扩展
Media Type | Description |
---|---|
application/json | JSON format |
application/xml | XML format |
application/yaml | YAML format |
application/octet-stream | Binary data |
application/grpc | gRPC format |
application/grpc+proto | gRPC with Protocol Buffers |
application/x-www-form-urlencoded | URL-encoded form data |
multipart/form-data | Form data with file upload |
text/json | JSON format as text |
text/xml | XML format as text |
text/yaml | YAML format as text |
text/css | CSS format |
text/javascript | JavaScript format as text |
text/html | HTML format |
text/plain | Plain text |
支持完善的内容协商机制,可根据映射或输入来协商输出的 Content-Type,具体流程如下:
@RequestMapping(produces = "application/json")
Accept
头,并将通配符匹配到合适的 Media Type。例如:
Accept: application/json
/hello?format=yml
/hello.txt
Content-Type: application/json
application/json
兜底
提供完整的CORS支持,通过配置全局参数即可启用,默认行为和SpringMVC一致,同时在SpringMVC方言中,也支持通过
@CrossOrigin
来做精细化配置。
支持的CORS 配置项参见:8.4CORS配置
很多场景需要对HTTP输出进行定制,比如做302跳转,写Http头,为此 Triple Rest提供以下通用方案,同时也支持各方言的特定写法,详情参见各方言使用指南
org.apache.dubbo.remoting.http12.HttpResult
可通过 HttpResult#builder
来构建throws new org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException(HttpResult)
示例代码:throw new HttpResult.found("https://a.com").
toPayload();
此异常已避免填充错误栈,对性能无太大影响,并且不用考虑返回值逻辑,推荐用这个方式来定制输出
HttpResponse response = RpcContext.getServiceContext().getRequest(HttpResponse.class);
response.
sendRedirect("https://a.com");
response.
setStatus(404);
response.
outputStream().
write(data);
// 写完输出建议 commit 来避免被其他扩展改写
response.
commit();
支持Jackson、fastjson2、fastjson和gson等多种JSON框架,使用前请确保对应jar依赖已被引入
dubbo.protocol.triple.rest.json-framework=jackson
可通过实现 SPI org.apache.dubbo.common.json.JsonUtil
方式来自定义JSON处理,具体可以参考 org/apache/dubbo/common/json/impl 已有实现,建议继承现有实现并重写
未被处理的异常最终被转换成 ErrorResponse
类编码后输出:
@Data
public class ErrorResponse {
/**
* http status code
*/
private String status;
/**
* exception message
*/
private String message;
}
注意对于500及以上错误,为避免泄露服务端内部信息,默认只会输出 message “Internal Server Error”,如果需要自定义 message 可创建继承自
org.apache.dubbo.remoting.http12.exception.HttpStatusException
异常并重写
getDisplayMessage
方法。
提供了以下通用方法来定制异常处理:
org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter
org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter
来转换异常,使用上更轻量并提供路径匹配配置能力注意后2项只能拦截 invoke 链中出现的异常,如果在路径匹配阶段出现异常,只有有方法1能处理
示例参见:dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic
Basic做为开箱即用 Rest 映射,默认会将方法映射到: /{contextPath}/{serviceInterface}/{methodName}
,其中
/{contextPath}
如果协议没有配置会忽略,即为:/{serviceInterface}/{methodName}
映射的自定义通过注解
org.apache.dubbo.remoting.http12.rest.Mapping
来支持,属性说明如下:
配置名 | 说明 | 默认行为 |
---|---|---|
value | 映射的 URL 路径,可以是一个或多个路径。 | 空数组 |
path | 映射的 URL 路径,与 value 相同,可以是一个或多个路径。 | 空数组 |
method | 支持的 HTTP 方法列表,例如 GET 、POST 等。 | 空数组(支持所有方法) |
params | 请求必须包含的参数列表。 | 空数组 |
headers | 请求必须包含的头部列表。 | 空数组 |
consumes | 处理请求的内容类型(Content-Type),可以是一个或多个类型。 | 空数组 |
produces | 生成响应的内容类型(Content-Type),可以是一个或多个类型。 | 空数组 |
enabled | 是否启用该映射。 | true (启用) |
通用入参见:3.2入参类型
Basic
的无注解参数由类:FallbackArgumentResolver.java
支持,具体处理流程如下:
示例参见:dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc
直接参考SpringMVC文档即可,支持绝大多数特性,Mapping Requests :: Spring Framework
注意无需
@Controller
或 @RestController
注解,除了 @RequestMapping
还支持新的 @HttpExchange
参见:3.2入参类型
参见 3.2.1通用类型参数
类型 | 说明 | 激活条件 |
---|---|---|
org.springframework.web.context.request.WebRequest | WebRequest对象 | 引入SpringWeb依赖 |
org.springframework.web.context.request.NativeWebRequest | NativeWebRequest对象 | 同上 |
org.springframework.http.HttpEntity | Http实体 | 同上 |
org.springframework.http.HttpHeaders | Http头 | 同上 |
org.springframework.util.MultiValueMap | 多值Map | 同上 |
优先使用 Spring 的 org.springframework.core.convert.ConversionService
来转换参数,如果应用为spring boot应用则默认使用
mvcConversionService
否则使用
org.springframework.core.convert.support.DefaultConversionService#getSharedInstance
获取共享
ConversionService
如果 ConversionService
不支持则会回退到通用类型转换:3.3参数类型转换
除了支持 3.8异常处理 中提到的方式,还支持 Spring
@ExceptionHandler
注解方式,Exceptions :: Spring Framework
,注意通过这种方式仅能处理方法调用时抛出的异常,其他异常无法捕获
除了支持 8.4CORS配置 全局配置,还支持 Spring
@CrossOrigin
来精细化配置,CORS :: Spring Framework
支持以下 Spring 自定义方式:
示例参见:dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs
Service需要显式添加注解@Path,方法需要添加@GET、@POST、@HEAD等请求方法注解
直接参考Resteasy文档即可,支持绝大多数特性,Chapter 4. Using @Path and @GET, @POST, etc
参见:3.2入参类型
注解 | 参数位置 | 说明 |
---|---|---|
@QueryParam | querystring | ?a=a&b=b对应的参数 |
@HeaderParam | header | |
@PathParam | path | |
@FormParam | form | body为key1=value2&key2=value2格式 |
无注解 | body | 不显式使用注解 |
类型 | 说明 | 激活条件 |
---|---|---|
javax.ws.rs.core.Cookie | Cookie对象 | 引入Jax-rs依赖 |
javax.ws.rs.core.Form | 表单对象 | 同上 |
javax.ws.rs.core.HttpHeaders | Http头 | 同上 |
javax.ws.rs.core.MediaType | 媒体类型 | 同上 |
javax.ws.rs.core.MultivaluedMap | 多值Map | 同上 |
javax.ws.rs.core.UriInfo | Uri信息 | 同上 |
可通过扩展自定义参数转换,扩展接口:
org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver
javax.ws.rs.ext.ParamConverterProvider
可通过扩展自定义异常处理,扩展接口:
javax.ws.rs.ext.ExceptionMapper
org.apache.dubbo.remoting.http12.ExceptionHandler
支持 8.4CORS配置 全局配置
支持以下 Jaxrs 自定义方式:
同时低版本javax和高版本jakarta servlet API,jakarta API 优先级更高,只需要引入jar即可使用HttpServletRequest和HttpServletResponse作为参数
方法1,实现 Filter
接口和 org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension
接口,然后注册SPI
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension;
import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class DemoFilter implements Filter, RestExtension {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
chain.doFilter(request, response);
}
@Override
public String[] getPatterns() {
return new String[]{"/demo/**", "!/demo/one"};
}
@Override
public int getPriority() {
return -200;
}
}
方法2,实现 Supplier<Filter>
接口和 org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension
接口,然后注册SPI
public class DemoFilter implements Supplier<Filter>, RestExtension {
private final Filter filter = new SsoFilter();
@Override
public Filter get() {
return filter;
}
}
这种方式对于重用已有 Filter 非常方便,甚至可以从 Spring Context 中获取 Filter 实例并注册
public class DemoFilter implements Supplier<Filter>, RestExtension {
private final Filter filter = new SsoFilter();
public DemoFilter(FrameworkModel frameworkModel) {
SpringExtensionInjector injector = SpringExtensionInjector.get(frameworkModel.defaultApplication());
filter = injector.getInstance(SsoFilter.class, null);
}
@Override
public Filter get() {
return filter;
}
}
实现 SPI org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory
request.getRequestDispatcher
当 REST 服务直接暴露在公网时,存在被攻击的安全风险。因此在暴露服务之前,需要充分评估风险并选择合适的认证方式来保证安全性。Triple 提供了多种安全认证机制,同时用户也可以自行实现相应的扩展来对访问进行安全校验。
要启用 Basic 认证,请修改以下配置:
dubbo:
provider:
auth: true
authenticator: basic
username: admin
password: admin
启用后,所有 HTTP 请求都需要通过 Basic 认证才能访问。
如果是 RPC 调用,还需要在消费者端配置相应的用户名和密码:
dubbo:
consumer:
auth: true
authenticator: basic
username: admin
password: admin
这样配置后,provider 和 consumer 之间的通信将使用 Basic 认证来保证安全性。请确保在生产环境中使用强密码,并考虑采用 HTTPS 来加密传输。
可通过 SPI org.apache.dubbo.auth.spi.Authenticator
来自定义认证,并通过配置 dubbo.provider.authenticator 来选择启用的 Authenticator
可通过 SPI org.apache.dubbo.rpc.HeaderFilter
或 org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter
来自定义 HTTP 过滤器逻辑
配置名:dubbo.protocol.triple.rest.case-sensitive-match
是否路径匹配应区分大小写。如果启用,映射到 /users
的方法不会匹配到
/Users
默认为 true
配置名:dubbo.protocol.triple.rest.trailing-slash-match
是否路径匹配应匹配带有尾部斜杠的路径。如果启用,映射到
/users
的方法也会匹配到 /users/
默认为 true
配置名:dubbo.protocol.triple.rest.suffix-pattern-match
是否路径匹配使用后缀模式匹配(.*) ,如果启用,映射到
/users
的方法也会匹配到 /users.*
,后缀内容协商会被同时启用,媒体类型从URL后缀推断,例如 .json
对应
application/json
默认为 true
配置名 | 说明 | 默认值 |
---|---|---|
dubbo.protocol.triple.rest.cors.allowed-origins | 允许跨域请求的来源列表,可以是具体域名或特殊值 * 代表所有来源。 | 未设置(不允许任何来源) |
dubbo.protocol.triple.rest.cors.allowed-methods | 允许的 HTTP 方法列表,例如 GET 、POST 、PUT 等,特殊值 * 代表所有方法。 | 未设置(仅允许 GET 和 HEAD ) |
dubbo.protocol.triple.rest.cors.allowed-headers | 预检请求中允许的请求头列表,特殊值 * 代表所有请求头。 | 未设置 |
dubbo.protocol.triple.rest.cors.exposed-headers | 实际响应中可以暴露给客户端的响应头列表,特殊值 * 代表所有响应头。 | 未设置 |
dubbo.protocol.triple.rest.cors.allow-credentials | 是否支持用户凭证。 | 未设置(不支持用户凭证) |
dubbo.protocol.triple.rest.cors.max-age | 预检请求的响应可以被客户端缓存的时间(以秒为单位)。 | 未设置 |
通过 SPI org.apache.dubbo.remoting.http12.ExceptionHandler
来自定义异常处理逻辑
public interface ExceptionHandler<E extends Throwable, T> {
/**
* Resolves the log level for a given throwable.
*/
default Level resolveLogLevel(E throwable) {
return null;
}
/**
* Handle the exception and return a result.
*/
default T handle(E throwable, RequestMetadata metadata, MethodDescriptor descriptor) {
return null;
}
}
实现 SPI 并将泛型 E 指定为需要处理的异常类型
org.apache.dubbo.remoting.http12.HttpResult
来定制输出的 headers 和 status code。
logging:
level:
"org.apache.dubbo.rpc.protocol.tri": debug
"org.apache.dubbo.remoting": debug
开启 debug 日志会输出详细的启动日志和请求响应日志,便于排查问题。
dubbo:
protocol:
triple:
verbose: true
开启 verbose 输出会将内部错误堆栈返回给调用方,并输出更多错误日志,便于排查问题。