Triple Rest User Manual

Introduction

Since Dubbo 3.3, the Triple protocol reuses the existing HTTP stack to fully support RESTful service exports. Without the need for generic or gateway protocol conversion, users can directly access backend Triple protocol services via HTTP in a decentralized manner. Additionally, it offers extensive annotation and SPI extension support for advanced REST usage, such as path customization, output format customization, and exception handling. Key features include:

  • Triple Protocol Integration
    Reuses the existing Triple HTTP stack, allowing support for HTTP/1, HTTP/2, and HTTP/3 without additional configuration or new ports.
  • Decentralization
    Exposes Rest APIs directly, eliminating dependency on gateway applications for traffic forwarding, thus improving performance and reducing stability risks caused by gateways. Security concerns can be addressed through internal application extensions, a practice verified in Taobao’s MTOP.
  • Support for Existing Servlet Infrastructure
    Supports Servlet API and Filter, allowing users to reuse existing security components based on the Servlet API. Integrating OAuth and Spring Security is as simple as implementing a Servlet Filter.
  • Multiple Dialects
    Considering that most users are accustomed to using SpringMVC or JAX-RS for REST API development, Triple Rest allows continued use of these methods for service definitions and supports most extensions and exception handling mechanisms (with over 80% of the original framework’s functionality). For lightweight users, the Basic dialect is available, and Triple’s out-of-the-box REST capabilities are based on this dialect.
  • High Extensibility
    Offers more than 20 extension points, enabling users to easily create custom dialects and flexibly customize parameter retrieval, type conversion, error handling, and other logic.
  • Out-of-the-Box
    REST capabilities are available out of the box; simply enable the Triple protocol to have direct REST access to services.
  • High-Performance Routing
    The routing component uses an optimized Radix Tree and Zero Copy technology to improve routing performance.
  • Seamless OpenAPI Integration (TBD)
    Upcoming OpenAPI integration will allow for out-of-the-box OpenAPI Schema export. With the Swagger dependency, a Web UI can be used for service testing. Using the OpenAPI Schema, API tools like Postman and Apifox can manage and test APIs, and the OpenAPI ecosystem can facilitate cross-language calls. Future enhancements will support a Schema First approach, allowing frontend teams to define OpenAPI collaboratively, generate call code and mocks based on OpenAPI, and enable backend development using stubs generated from OpenAPI, greatly improving collaboration efficiency.

Quick Start

Let’s explore Triple Rest with a simple example. You can directly download the existing sample project to get started quickly. Assume you have Java, Maven, and Git installed.

Download and Run the Example

# Get the sample code
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
# Run directly
mvn spring-boot:run
# Or package and run
mvn clean package -DskipTests
java -jar target/dubbo-samples-triple-rest-basic-1.0.0-SNAPSHOT.jar

Alternatively, you can import the project into your IDE and directly execute org.apache.dubbo.rest.demo.BasicRestApplication#main to run it. You can also debug by setting breakpoints to deeply understand the principles.

Example Code

// Service Interface
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);
}

// Service Implementation
@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;
    }
}

// Model
@Data
public class User {
    private String title;
    private String name;
}

Test the Basic Service

curl -v "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hello?name=world"
# Output:
#> 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"

Explanation:
You see the output "Hello world". The quotes are because the default content-type is application/json. This example demonstrates how Triple exports services to the /{serviceInterface}/{methodName} path by default and supports passing parameters via URL.

Test the Advanced Service

curl -v -H "c: 3" -d 'name=Yang' "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr"
# Output:
#> 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

Explanation:
The output "Hello Mr. Yang, 3" has no quotes because the .txt suffix was specified to request text/plain output. This example shows how to customize paths using the Mapping annotation, customize parameter sources with the Param annotation, and pass parameters via post body or URL. For more details, see the Basic Usage Guide

Observe Logs

Enable debug logging to understand the rest startup and request response process:

logging:
  level:
    "org.apache.dubbo.rpc.protocol.tri": debug
    "org.apache.dubbo.remoting": debug

Once enabled, you can observe the Rest mapping registration and request process:

# Register 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]}

General Features

Path Mapping

The Triple protocol is compatible with both SpringMVC and JAX-RS mapping methods. For more information, refer to:

You can also customize path mapping by implementing the SPI org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver.

Supported Patterns

  1. books: A string constant matching a fixed segment.
  2. ?: Matches a single character.
  3. *: Matches zero or more characters within a path segment.
  4. **: Matches zero or more path segments until the end of the path.
  5. {spring}: Matches a path segment and captures it as a variable named “spring.”
  6. {spring:[a-z]+}: Uses a regular expression [a-z]+ to match a path segment and captures it as a variable named “spring.”
  7. {*spring}: Matches zero or more path segments until the end of the path and captures them as a variable named “spring.” {*} without a variable name indicates that no capturing is done.

Examples (from Spring Documentation)

  • /pages/t?st.html: Matches /pages/test.html and /pages/tXst.html, but not /pages/toast.html.
  • /resources/*.png: Matches all .png files in the resources directory.
  • com/**/test.jsp: Matches all test.jsp files under the com path.
  • org/springframework/**/*.jsp: Matches all .jsp files under the org/springframework path.
  • /resources/**: Matches all files under the /resources/ path, including /resources/image.png and /resources/css/spring.css.
  • /resources/{*path}: Matches all files under /resources/ as well as /resources itself, capturing the relative path as the variable “path.” For example, /resources/image.png would map to “path” → “/image.png”, and /resources/css/spring.css would map to “path” → “/css/spring.css”.
  • /resources/{filename:\\w+}.dat: Matches /resources/spring.dat and assigns the value “spring” to the filename variable.
  • /{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}: Matches /example-2.1.5.html, with name as example, version as 2.1.5, and ext as .html.

Tip: If you do not want the regular expression to span multiple segments, use {name:[^/]+}.

Full Mapping Process

The detailed matching logic is implemented in the following code: DefaultRequestMappingRegistry.java, RequestMapping.java.

  1. Normalize the path using PathUtils.normalize to remove indirect paths such as /one/../ or /one/./, ensuring the path starts with /.
  2. Check if the HTTP method matches.
  3. Check if the path matches.
  4. Check if the parameter matches (not supported by JAX-RS).
  5. Check if the header matches.
  6. Check if the content type matches (Consumes).
  7. Check if the accept header matches (Produces).
  8. Check if serviceGroup and serviceVersion match.
  9. Check if the method signature matches.
  10. If no match is found, retry after removing the trailing / if trailing slash matching is enabled.
  11. If no match is found, retry after removing the extension if extension matching is enabled.
  12. If the last path segment contains ~, retry with method signature matching enabled.
  13. If no candidates remain, return null.
  14. If one candidate remains, return it.
  15. If multiple candidates remain, sort them.
  16. Compare the first and second candidates.
  17. If the result is inconclusive, throw an exception.
  18. If the first candidate wins, return it.

Handling Path Conflicts

Unlike Spring, which raises an error and prevents startup when paths are identical, Triple Rest focuses on out-of-the-box usage. To avoid disrupting existing services, it logs a warning by default. At runtime, if it cannot determine the highest priority mapping, an error will be thrown.

Parameter Types

Supported parameter types vary by dialect. Please refer to the specific dialect’s guide for more details. You can also customize parameter resolution by implementing the SPI org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver.

Common Parameter Types

NameDescriptionBasic AnnotationSpringMVC AnnotationJAX-RS AnnotationArray or Collection HandlingMap Handling
ParamQuery or Form parameter@Param@RequestParam-Multi-valueMap of all parameters
QueryURL parameter--@QueryParamMulti-valueMap of all Query parameters
FormForm parameter--@FormParamMulti-valueMap of all Form parameters
HeaderHTTP header@Param(type=Header)@RequestHeader@HeaderParamMulti-valueMap of all Headers
CookieCookie value@Param(type=Cookie)@CookieValue@CookieParamMulti-valueMap of all Cookies
AttributeRequest attribute@Param(type=Attribute)@RequestAttribute-Multi-valueMap of all Attributes
PartMultipart file@Param(type=Part)@RequestHeader@HeaderParamMulti-valueMap of all Parts
BodyRequest body@Param(type=Body)@RequestBody@BodyAttempts to parse as array or collectionAttempts to parse as target type
PathVariablePath variable@Param(type=PathVariable)@PathVariable@PathParamSingle-value array or collectionSingle-value Map
MatrixVariableMatrix variable@Param(type=MatrixVariable)@MatrixVariable@MatrixParamMulti-valueSingle-value Map
BeanJava BeanNo annotation needed@ModelAttribute@BeanParamAttempts to parse as Bean array or collection-

Special Parameter Types

TypeDescriptionActivation Condition
org.apache.dubbo.remoting.http12.HttpRequestHttpRequest objectActivated by default
org.apache.dubbo.remoting.http12.HttpResponseHttpResponse objectActivated by default
org.apache.dubbo.remoting.http12.HttpMethodsHTTP request methodActivated by default
java.util.LocaleRequest LocaleActivated by default
java.io.InputStreamRequest InputStreamActivated by default
java.io.OutputStreamResponse OutputStreamActivated by default
javax.servlet.http.HttpServletRequestServlet HttpRequest objectRequires Servlet API jar
javax.servlet.http.HttpServletResponseServlet HttpResponse objectSame as above
javax.servlet.http.HttpSessionServlet HttpSession objectSame as above
javax.servlet.http.CookieServlet Cookie objectSame as above
java.io.ReaderServlet Request Reader objectSame as above
java.io.WriterServlet Response Writer objectSame as above

Parameters without Annotations

The handling varies by dialect; refer to the specific dialect’s guide.

Accessing HTTP Input and Output Parameters without Annotations

You can use RpcContext to retrieve them:

// 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);

After obtaining the request, you can access some built-in attributes through attribute. See: RestConstants.java

Parameter Type Conversion

By default, most parameter type conversions from String to target types are supported, including:

  • JDK built-in types (e.g., basic types, date, Optional, etc.)
  • Array types
  • Collection types
  • Map types

Generic types, including complex nesting, are fully supported. For implementation details, refer to: GeneralTypeConverter.java. Custom parameter type conversion can also be achieved by implementing SPI org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter.

Source TypeTarget TypeDescriptionDefault Value
StringdoubleConverts to a double0.0d
StringfloatConverts to a float0.0f
StringlongConverts to a long0L
StringintConverts to an integer0
StringshortConverts to a short0
StringcharConverts to a character0
StringbyteConverts to a byte0
StringbooleanConverts to a booleanfalse
StringBigIntegerConverts to a BigIntegernull
StringBigDecimalConverts to a BigDecimalnull
StringDateConverts to a Datenull
StringCalendarConverts to a Calendarnull
StringTimestampConverts to a Timestampnull
StringInstantConverts to an Instantnull
StringZonedDateTimeConverts to a ZonedDateTimenull
StringLocalDateConverts to a LocalDatenull
StringLocalTimeConverts to a LocalTimenull
StringLocalDateTimeConverts to a LocalDateTimenull
StringZoneIdConverts to a ZoneIdnull
StringTimeZoneConverts to a TimeZonenull
StringFileConverts to a Filenull
StringPathConverts to a Pathnull
StringCharsetConverts to a Charsetnull
StringInetAddressConverts to an InetAddressnull
StringURIConverts to a URInull
StringURLConverts to a URLnull
StringUUIDConverts to a UUIDnull
StringLocaleConverts to a Localenull
StringCurrencyConverts to a Currencynull
StringPatternConverts to a Patternnull
StringClassConverts to a Classnull
Stringbyte[]Converts to a byte arraynull
Stringchar[]Converts to a char arraynull
StringOptionalIntConverts to an OptionalIntnull
StringOptionalLongConverts to an OptionalLongnull
StringOptionalDoubleConverts to an OptionalDoublenull
StringEnum classEnum.valueOfnull
StringArray or CollectionSplit by commanull
StringSpecified classTry JSON String to Objectnull
StringSpecified classTry construct with single Stringnull
StringSpecified classTry call static method valueOfnull

Supported Content-Types

By default, the following Content-Types are supported with corresponding encoding and decoding capabilities. Extension is available by implementing SPI org.apache.dubbo.remoting.http12.message.(HttpMessageDecoderFactory|HttpMessageEncoderFactory).

Media TypeDescription
application/jsonJSON format
application/xmlXML format
application/yamlYAML format
application/octet-streamBinary data
application/grpcgRPC format
application/grpc+protogRPC with Protocol Buffers
application/x-www-form-urlencodedURL-encoded form data
multipart/form-dataForm data with file upload
text/jsonJSON format as text
text/xmlXML format as text
text/yamlYAML format as text
text/cssCSS format
text/javascriptJavaScript format as text
text/htmlHTML format
text/plainPlain text

Content Negotiation

Supports comprehensive content negotiation to determine the output Content-Type based on mapping or input. The process is as follows:

  1. Try to read the mediaType specified by Mapping, retrieve the list of mediaTypes specified by Produces, and match wildcard to appropriate Media Type. For example, Spring’s: @RequestMapping(produces = "application/json")
  2. Try to find mediaType using the Accept header, parse the request’s Accept header, and match wildcard to appropriate Media Type. For example: Accept: application/json
  3. Try to find mediaType using the format parameter, read the format parameter value, and match it to an appropriate Media Type. For example /hello?format=yml
  4. Try to find mediaType using the request path extension, match the extension to an appropriate Media Type. For example /hello.txt
  5. Try to use the request’s Content-Type header as Media Type (excluding two form types). For example Content-Type: application/json
  6. Default to application/json

CORS Support

Provides full CORS support, enabled by configuring global parameters. Default behavior is consistent with SpringMVC. Fine-grained configuration is also supported through @CrossOrigin in SpringMVC. For supported CORS configuration items, refer to: 8.4 CORS Configuration

Custom HTTP Output

Custom HTTP output is required in many scenarios, such as 302 redirects or setting HTTP headers. Triple Rest offers the following generic solutions, with dialect-specific approaches available in each dialect’s user guide:

  • Set the return value to: org.apache.dubbo.remoting.http12.HttpResult and build using HttpResult#builder.
  • Throw a Payload exception: throws new org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException(HttpResult). Example code:
throw new HttpResult.found("https://a.com").

toPayload();

This exception avoids filling error stacks, has minimal performance impact, and does not require return value logic, making it recommended for customizing output.

  • Customize after obtaining HttpResponse. Example code:
HttpResponse response = RpcContext.getServiceContext().getRequest(HttpResponse.class);

response.

sendRedirect("https://a.com");
response.

setStatus(404);
response.

outputStream().

write(data);
// It is recommended to commit after writing to avoid being modified by other extensions
response.

commit();

If only adding http headers, use this method.

Custom JSON Serialization

Multiple JSON frameworks are supported, including Jackson, fastjson2, fastjson, and gson. Please ensure that the corresponding jar dependencies have been imported before use.

Specifying the JSON Framework to Use

dubbo.protocol.triple.rest.json-framework=jackson

Customization through JsonUtil SPI

You can customize JSON processing by implementing the SPI org.apache.dubbo.common.json.JsonUtil. For specific examples, you can refer to the existing implementations in org/apache/dubbo/common/json/impl. It is recommended to extend an existing implementation and override as needed.

Exception Handling

Unhandled exceptions are ultimately converted to the ErrorResponse class and encoded for output:


@Data
public class ErrorResponse {
    /**
     * HTTP status code
     */
    private String status;

    /**
     * Exception message
     */
    private String message;
}

Note that for errors with status 500 and above, to avoid disclosing internal server information, the default message output is “Internal Server Error”. To customize the message, create an exception that extends org.apache.dubbo.remoting.http12.exception.HttpStatusException and override the getDisplayMessage method.
The following general methods are available for customizing exception handling:

  • Refer to 9.2 Custom Exception Return Results for using SPI to customize global exception handling.
  • Use Dubbo’s Filter SPI to process and transform exceptions. To access the HTTP context, extend org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter.
  • Use SPI org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter to transform exceptions, which is more lightweight and provides path matching configuration capabilities.

Note that the latter two methods only intercept exceptions occurring in the invoke chain. If exceptions occur during path matching, only method 1 can handle them.

Basic Usage Guide

See example: dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic

Path Mapping

Basic, as an out-of-the-box REST mapping, will by default map methods to: /{contextPath}/{serviceInterface}/{methodName}, where /{contextPath} will be ignored if not configured, resulting in: /{serviceInterface}/{methodName}.
Custom mappings are supported through the org.apache.dubbo.remoting.http12.rest.Mapping annotation. The attribute descriptions are as follows:

Config NameDescriptionDefault Behavior
valueMapped URL paths, which can be one or more paths.Empty array
pathMapped URL paths, same as value, can be one or more paths.Empty array
methodSupported HTTP methods list, such as GET, POST, etc.Empty array (supports all methods)
paramsList of parameters that must be included in the request.Empty array
headersList of headers that must be included in the request.Empty array
consumesContent types (Content-Type) for processing requests, which can be one or more types.Empty array
producesContent types (Content-Type) for generating responses, which can be one or more types.Empty array
enabledWhether to enable this mapping.true (enabled)
  • Attributes can be configured using placeholders: @Mapping("${prefix}/hi")
  • To prevent a specific service or method from being exported as REST, set @Mapping(enabled = false)

Parameter Types

General parameters are discussed in: 3.2 Parameter Types

Parameters Without Annotations

Basic supports parameters without annotations through the class: FallbackArgumentResolver.java. The detailed processing flow is as follows:
rest-arg.jpg

SpringMVC Usage Guide

See example: dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc

Path Mapping

Refer directly to the SpringMVC documentation, which supports most features, Mapping Requests :: Spring Framework
Note that @Controller or @RestController annotations are not required; in addition to @RequestMapping, the new @HttpExchange is also supported.

Parameter Types

General Parameters

See: 3.2 Parameter Types

Annotated Parameter Types

See 3.2.1 Annotated Parameter Types

Special Parameter Types

TypeDescriptionActivation Condition
org.springframework.web.context.request.WebRequestWebRequest objectSpringWeb dependency required
org.springframework.web.context.request.NativeWebRequestNativeWebRequest objectSame as above
org.springframework.http.HttpEntityHttp entitySame as above
org.springframework.http.HttpHeadersHttp headersSame as above
org.springframework.util.MultiValueMapMulti-value mapSame as above

Parameters Without Annotations

Parameter Type Conversion

Prefer using Spring’s org.springframework.core.convert.ConversionService to convert parameters. For Spring Boot applications, the default is mvcConversionService; otherwise, use org.springframework.core.convert.support.DefaultConversionService#getSharedInstance to obtain the shared ConversionService.
If ConversionService does not support it, it will fall back to general type conversion: 3.3 Parameter Type Conversion

Exception Handling

In addition to supporting the methods mentioned in 3.8 Exception Handling, Spring’s @ExceptionHandler annotation method is also supported, Exceptions :: Spring Framework. Note that this method only handles exceptions thrown during method calls; other exceptions cannot be captured.

CORS Configuration

In addition to supporting global CORS configuration as described in 8.4 CORS Configuration, Spring’s @CrossOrigin allows for fine-grained configuration, CORS :: Spring Framework.

Custom HTTP Output

Supports the following Spring customization methods:

  1. Use @ResponseStatus annotation
  2. Return org.springframework.http.ResponseEntity object

Supported Extensions

JAX-RS Usage Guide

See example: dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs

Path Mapping

Services need to explicitly add the @Path annotation, and methods need to add request method annotations like @GET, @POST, @HEAD.
Refer directly to the Resteasy documentation, which supports most features, Chapter 4. Using @Path and @GET, @POST, etc.

Parameter Types

General Parameters

See: 3.2 Parameter Types

Annotation Type Parameters

AnnotationParameter LocationDescription
@QueryParamquerystringParameters corresponding to ?a=a&b=b
@HeaderParamheader
@PathParampath
@FormParamformbody in key1=value2&key2=value2 format
No annotationbodyNot explicitly annotated

Special Type Parameters

TypeDescriptionActivation Condition
javax.ws.rs.core.CookieCookie objectRequires Jax-rs dependency
javax.ws.rs.core.FormForm objectSame as above
javax.ws.rs.core.HttpHeadersHttp headersSame as above
javax.ws.rs.core.MediaTypeMedia typeSame as above
javax.ws.rs.core.MultivaluedMapMultivalued MapSame as above
javax.ws.rs.core.UriInfoUri informationSame as above

Non-Annotated Parameters

  • For basic types (as determined by TypeUtils#isSimpleProperty), directly retrieved from Parameter
  • For non-basic types, treated as request body to decode the object

Parameter Type Conversion

Custom parameter conversion can be extended via the following interfaces:

org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver
javax.ws.rs.ext.ParamConverterProvider

Exception Handling

Custom exception handling can be extended via the following interfaces:

javax.ws.rs.ext.ExceptionMapper
org.apache.dubbo.remoting.http12.ExceptionHandler

CORS Configuration

Supports 8.4 CORS Configuration global configuration

Custom HTTP Output

Supports the following JAX-RS customizations:

  • Returning javax.ws.rs.core.Response object

Supported Extensions

  1. javax.ws.rs.container.ContainerRequestFilter
    Request filter, allows pre-processing of requests before they reach the resource method.
  2. javax.ws.rs.container.ContainerResponseFilter
    Response filter, allows post-processing of responses after they leave the resource method.
  3. javax.ws.rs.ext.ExceptionMapper
    Exception mapper, maps thrown exceptions to HTTP responses.
  4. javax.ws.rs.ext.ParamConverterProvider
    Parameter converter, allows conversion of request parameters to resource method parameter types.
  5. javax.ws.rs.ext.ReaderInterceptor
    Reader interceptor, allows interception and handling when reading request entities.
  6. javax.ws.rs.ext.WriterInterceptor
    Writer interceptor, allows interception and handling when writing response entities.

Servlet Usage Guide

For both lower version javax and higher version jakarta servlet APIs, jakarta API has higher priority. Simply include the jar to use HttpServletRequest and HttpServletResponse as parameters.

Using Filter Extension

Method 1: Implement Filter interface and org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension interface, then register 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;
    }
}

Method 2: Implement Supplier<Filter> interface and org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension interface, then register SPI

public class DemoFilter implements Supplier<Filter>, RestExtension {

    private final Filter filter = new SsoFilter();

    @Override
    public Filter get() {
        return filter;
    }
}

This method is convenient for reusing existing Filters, and can even obtain Filter instances from Spring Context and register them

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;
    }
}

HttpSession Support

Implement SPI org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory

Unsupported Features

  • Wrapping request and response objects in Filter will not work due to the large number of filter types supported by Rest, leading to complex nesting and handling.
  • request.getRequestDispatcher is not supported

Security Configuration

When Rest services open direct access to the public network, there are security risks of potential attacks. Therefore, before exposing services, it’s necessary to thoroughly assess the risks and choose appropriate authentication methods to ensure security. Triple provides various security authentication mechanisms, and users can also implement their own extensions to perform security checks on access.

Basic Authentication

To enable Basic Authentication, modify the following configuration:

dubbo:
  provider:
    auth: true
    authenticator: basic
    username: admin
    password: admin

Once enabled, all HTTP requests will require Basic Authentication to access.

For RPC calls, you also need to configure the corresponding username and password on the consumer side:

dubbo:
  consumer:
    auth: true
    authenticator: basic
    username: admin
    password: admin

With this configuration, communication between provider and consumer will use Basic Authentication to ensure security. Make sure to use strong passwords in production environments and consider using HTTPS for encrypted transmission.

Authentication Extensions

Implementing Custom Authenticator

You can customize authentication by implementing the SPI org.apache.dubbo.auth.spi.Authenticator, and select the Authenticator to enable through the configuration dubbo.provider.authenticator.

Implementing HTTP Request Filtering

You can customize HTTP filtering logic by implementing the SPI org.apache.dubbo.rpc.HeaderFilter or org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.

Global Parameter Configuration

Case Sensitivity

Configuration Name: dubbo.protocol.triple.rest.case-sensitive-match
Whether path matching should be case-sensitive. If enabled, methods mapped to /users will not match /Users
Default is true

Trailing Slash Matching

Configuration Name: dubbo.protocol.triple.rest.trailing-slash-match
Whether path matching should match paths with trailing slashes. If enabled, methods mapped to /users will also match /users/
Default is true

Suffix Matching

Configuration Name: dubbo.protocol.triple.rest.suffix-pattern-match
Whether path matching uses suffix pattern matching (.*). If enabled, methods mapped to /users will also match /users.*, with suffix content negotiation enabled, media types inferred from URL suffix, e.g., .json corresponds to application/json
Default is true

CORS Configuration

Configuration NameDescriptionDefault Value
dubbo.protocol.triple.rest.cors.allowed-originsList of allowed origins for cross-origin requests, can be specific domains or * for all origins.Not set (no origins allowed)
dubbo.protocol.triple.rest.cors.allowed-methodsList of allowed HTTP methods, e.g., GET, POST, PUT, * for all methods.Not set (only GET and HEAD)
dubbo.protocol.triple.rest.cors.allowed-headersList of allowed request headers in preflight requests, * for all headers.Not set
dubbo.protocol.triple.rest.cors.exposed-headersList of response headers exposed to clients, * for all headers.Not set
dubbo.protocol.triple.rest.cors.allow-credentialsWhether user credentials are supported.Not set (user credentials not supported)
dubbo.protocol.triple.rest.cors.max-ageTime (in seconds) that the client can cache the preflight request response.Not set

Advanced Usage Guide

Summary of Supported Extensions

  1. javax.servlet.Filter
    Servlet API filter.
  2. org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory
    Supports HttpSession in Servlet API.
  3. javax.ws.rs.container.ContainerRequestFilter
    JAX-RS request filter, allows pre-processing of requests before they reach the resource method.
  4. javax.ws.rs.container.ContainerResponseFilter
    JAX-RS response filter, allows post-processing of responses after they leave the resource method.
  5. javax.ws.rs.ext.ExceptionMapper
    JAX-RS exception mapper, maps thrown exceptions to HTTP responses.
  6. javax.ws.rs.ext.ParamConverterProvider
    JAX-RS parameter converter, allows conversion of request parameters to resource method parameter types.
  7. javax.ws.rs.ext.ReaderInterceptor
    JAX-RS reader interceptor, allows interception and handling when reading request entities.
  8. javax.ws.rs.ext.WriterInterceptor
    JAX-RS writer interceptor, allows interception and handling when writing response entities.
  9. org.springframework.web.servlet.HandlerInterceptor
    Spring MVC handler interceptor.
  10. org.apache.dubbo.remoting.http12.ExceptionHandler
    Provides custom exception handling mechanism.
  11. org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory
    Provides adaptation and conversion functions for HTTP messages.
  12. org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
    Provides HTTP message decoding functions.
  13. org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
    Provides HTTP message encoding functions.
  14. org.apache.dubbo.rpc.HeaderFilter
    Dubbo RPC header filter, allows filtering and handling of request and response headers.
  15. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestHeaderFilterAdapter
    Header filter adapter providing access to HTTP input and output capabilities.
  16. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter
    Dubbo Filter REST adapter, providing access to HTTP input and output capabilities.
  17. org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping
    Provides request mapping capability in Dubbo Triple.
  18. org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver
    Resolves REST request mappings.
  19. org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit
    Provides REST-related tools and utilities.
  20. org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter
    Provides argument type conversion functionality.
  21. org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver
    Provides argument resolution functionality.
  22. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter
    Provides filtering functionality for REST requests and responses.
  23. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter
    RestExtension adapter providing mapping of existing filter interfaces to RestFilter interfaces.

Custom Exception Handling

Custom exception handling logic can be implemented via the 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;
    }
}

Implement SPI and specify the exception type E to handle

  • resolveLogLevel
    Dubbo framework will log Rest handling exceptions, customize log level or ignore logs by implementing this method.
  • handle
    If the result is not null, it will be directly returned; customize output headers and status code by returning org.apache.dubbo.remoting.http12.HttpResult.

Enable Debug Logging

logging:
  level:
    "org.apache.dubbo.rpc.protocol.tri": debug
    "org.apache.dubbo.remoting": debug

Enable debug logging will output detailed startup logs and request/response logs for troubleshooting.

Enable Verbose Output

dubbo:
  protocol:
    triple:
      verbose: true

Enable verbose output will return internal error stack traces to the caller and output more error logs for troubleshooting.

Last modified September 13, 2024: Refactor website structure (#2860) (1a4b998f54b)