diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/http.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/http.md index 53433653774f..bb943f4e0e39 100644 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/http.md +++ b/content/en/docs3-v2/java-sdk/reference-manual/protocol/http.md @@ -6,6 +6,11 @@ weight: 6 --- +{{% alert title="Note" color="warning" %}} +Since Dubbo 3.3, the rest protocol has been moved to the extensions library, with the triple protocol now providing more comprehensive support for Rest. For details refer to [Triple Rest User Manual](../../tripe-rest-manual/). +If you wish to continue using the original rest protocol, please include the corresponding [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) dependency. +{{% /alert %}} + ## Feature description HTTP form-based remote invocation protocol, implemented by Spring's HttpInvoker, supported by versions above `2.3.0`. diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/rest.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/rest.md index e20537a33ba7..d9acddd826a2 100644 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/rest.md +++ b/content/en/docs3-v2/java-sdk/reference-manual/protocol/rest.md @@ -5,6 +5,11 @@ linkTitle: "Rest protocol" weight: 4 --- +{{% alert title="Note" color="warning" %}} +Since Dubbo 3.3, the rest protocol has been moved to the extensions library, with the triple protocol now providing more comprehensive support for Rest. For details refer to [Triple Rest User Manual](../../tripe-rest-manual/). +If you wish to continue using the original rest protocol, please include the corresponding [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) dependency. +{{% /alert %}} + Support for REST calls based on the standard Java REST API - JAX-RS 2.0 (short for Java API for RESTful Web Services) ### Quick Start diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-3.3.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-3.3.md new file mode 100644 index 000000000000..c47723d8a230 --- /dev/null +++ b/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-3.3.md @@ -0,0 +1,282 @@ +--- +type: docs +title: "Tripe 3.3 New Features" +linkTitle: "Tripe 3.3 New Features" +weight: 13 +--- + + + +## New REST Support + +### Rest Features + +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. +- **Strong 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](https://github.com/apache/dubbo/blob/3.3/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java) 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](https://www.postman.com/) and [Apifox](https://apifox.com/) 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. + + + +### Example + + + +###### Sample Code + +```java +package org.apache.dubbo.rest.demo; + +import org.apache.dubbo.remoting.http12.rest.Mapping; +import org.apache.dubbo.remoting.http12.rest.Param; + +// Service Interface +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; +} +``` + + + +###### Download and Run Example + +```bash +# Get the example 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 +mvn spring-boot:run +``` + + + +###### Curl Test + +```bash +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 +#> +#< HTTP/1.1 200 OK +#< content-type: application/json +#< content-length: 13 +#< +#"Hello world" +# +# Explanation +# The output shows "Hello world", with quotes because the default content-type is application/json. +# This example shows that Triple exports services to the /{serviceInterface}/{methodName} path by default, supporting parameter passing via 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" +# Output +#> POST /org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr HTTP/1.1 +#> c: 3 +#> Content-Length: 9 +#> Content-Type: application/x-www-form-urlencoded +#> +#< HTTP/1.1 200 OK +#< content-type: text/plain +#< content-length: 17 +#< +#Hello Mr. Yang, 3 +# +# Explanation +# The output shows "Hello Mr. Yang, 3", without quotes because the output was specified as text/plain by using the txt suffix. +# This example shows how to customize paths using the Mapping annotation and customize parameter sources using the Param annotation, supporting parameter passing via post body or URL. +``` + + + +### Documentation + +Please visit the user manual: [Triple Rest Manual](../triple-rest-manual/) + + +## Support for Servlet Integration + +In version 3.3, you can reuse existing Spring Boot servlet listening ports to handle HTTP traffic, eliminating the need for Netty to listen on new ports. This simplifies deployment +and reduces maintenance costs. By reducing reliance on external ports, it helps to easily pass through enterprise firewalls and gateways, simplifying network deployment and +enhancing the maintainability and security of enterprise applications. + + +### Example + + + +###### Download and Run Example + +```bash +# Get the sample code +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-servlet +# Run directly +mvn spring-boot:run +``` + + + +###### Curl Test + +```shell +curl --http2-prior-knowledge -v 'http://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world' +# Output +#* [HTTP/2] [1] OPENED stream for http://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world +#* [HTTP/2] [1] [:method: GET] +#* [HTTP/2] [1] [:scheme: http] +#* [HTTP/2] [1] [:authority: localhost:50052] +#* [HTTP/2] [1] [:path: /org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world] +#> +#* Request completely sent off +#< HTTP/2 200 +#< content-type: application/json +#< date: Sun, 25 Aug 2024 03:38:12 GMT +#< +#"Hello world" +``` + + + +### Documentation + +Please +visit: [how-to-enable-servlet-support-for-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-servlet#how-to-enable-servlet-support-for-triple) +to learn how to configure and enable servlet support. + + +## Support for HTTP/3 Protocol + + + +### HTTP/3 Features + +In version 3.3, Triple implements support for the HTTP/3 protocol, allowing RPC and REST requests to be transmitted via HTTP/3. Using HTTP/3 offers the following benefits: + +- **Enhanced Performance** + With HTTP/3 support, the use of the QUIC protocol reduces latency and accelerates request-response times. This significantly boosts overall service + performance, especially in high-latency or complex network environments. +- **Improved Reliability** + HTTP/3 leverages multiplexing and connection migration to avoid head-of-line blocking, maintaining stable connections even under poor network conditions + and ensuring reliable service delivery. +- **Increased Security** + HTTP/3 enforces TLS 1.3 encryption, providing a more secure communication channel compared to the optional encryption in traditional HTTP/2. +- **Better Adaptation to Weak Networks** + In scenarios with high packet loss or unstable bandwidth, HTTP/3 maintains high connection quality and service performance, improving + outcomes in weak network environments. + +Since HTTP/3 is based on the QUIC protocol (UDP), it might be blocked by firewalls or gateways. To mitigate this, Triple has implemented HTTP/3 negotiation capabilities and enabled +it by default. Connections are initially established via HTTP/2, and if the server responds with an [Alt-Svc](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc) +header indicating HTTP/3 support, the client will automatically switch to HTTP/3. + + +### Example + + + +###### Download and Run Example + +```bash +# Get the sample code +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-http3 +# Run directly +mvn spring-boot:run +``` + + + +###### Testing with Curl + +Note that Curl must be upgraded to a version that supports HTTP/3. Refer to: [https://curl.se/docs/http3.html](https://curl.se/docs/http3.html). + +```shell + +curl --http3 -vk 'https://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world' +# Output +#* QUIC cipher selection: TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256 +#* Skipped certificate verification +#* using HTTP/3 +#* [HTTP/3] [0] OPENED stream for https://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world +#* [HTTP/3] [0] [:method: GET] +#* [HTTP/3] [0] [:scheme: https] +#* [HTTP/3] [0] [:authority: localhost:50052] +#* [HTTP/3] [0] [:path: /org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world] +#> +#* Request completely sent off +#< HTTP/3 200 +#< content-type: application/json +#< +#"Hello world" +``` + + + +### Performance Comparison + +#### Impact of Packet Loss on QPS + +![http3-qps.jpg](/imgs/v3/manual/java/protocol/http3-qps.jpg) + +#### Impact of Packet Loss on RT + +![http3-rt.jpg](/imgs/v3/manual/java/protocol/http3-rt.jpg) + + + +### Architecture Diagram + +![http3-arch.jpg](/imgs/v3/manual/java/protocol/http3-arch.jpg) + +### Documentation + +For information on how to configure and enable HTTP/3 support, please +visit: [how-to-enable-http3-support-for-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-http3#how-to-enable-http3-support-for-triple). diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-rest-manual.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-rest-manual.md new file mode 100644 index 000000000000..4c266e5833fe --- /dev/null +++ b/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-rest-manual.md @@ -0,0 +1,924 @@ +--- +linkTitle: Triple Rest User Manual +title: Triple Rest User Manual +type: docs +weight: 14 +--- + +{{% alert title="Note" color="warning" %}} +Since Dubbo 3.3, the original Rest protocol has been moved to the Extensions library, and the Triple protocol now provides more comprehensive support for Rest. To continue using +the original Rest protocol, you can add the corresponding [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) +library dependency. +{{% /alert %}} + +## 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. +- **Strong 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](https://github.com/apache/dubbo/blob/3.3/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java) 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](https://www.postman.com/) and [Apifox](https://apifox.com/) 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 + +```bash +# 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 + +```java +// 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 + +```bash +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 + +```bash +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](#GdlnC) + + +### Observe Logs + +Enable debug logging to understand the rest startup and request response process: + +```yaml +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: + +- [Spring Mapping Requests](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates) +- [Spring PathPattern](https://docs.spring.io/spring-framework/docs/6.1.12/javadoc-api/org/springframework/web/util/pattern/PathPattern.html) +- [Spring AntPathMatcher](https://docs.spring.io/spring-framework/docs/6.1.12/javadoc-api/org/springframework/util/AntPathMatcher.html) +- [JAX-RS Path and regular expression mappings](https://docs.jboss.org/resteasy/docs/6.2.7.Final/userguide/html/ch04.html) + +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](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java#L196), [RequestMapping.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java#L127). + +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 + +| Name | Description | Basic Annotation | SpringMVC Annotation | JAX-RS Annotation | Array or Collection Handling | Map Handling | +|----------------|-------------------------|-----------------------------|----------------------|-------------------|-----------------------------------------------|----------------------------------| +| Param | Query or Form parameter | @Param | @RequestParam | - | Multi-value | Map of all parameters | +| Query | URL parameter | - | - | @QueryParam | Multi-value | Map of all Query parameters | +| Form | Form parameter | - | - | @FormParam | Multi-value | Map of all Form parameters | +| Header | HTTP header | @Param(type=Header) | @RequestHeader | @HeaderParam | Multi-value | Map of all Headers | +| Cookie | Cookie value | @Param(type=Cookie) | @CookieValue | @CookieParam | Multi-value | Map of all Cookies | +| Attribute | Request attribute | @Param(type=Attribute) | @RequestAttribute | - | Multi-value | Map of all Attributes | +| Part | Multipart file | @Param(type=Part) | @RequestHeader | @HeaderParam | Multi-value | Map of all Parts | +| Body | Request body | @Param(type=Body) | @RequestBody | @Body | Attempts to parse as array or collection | Attempts to parse as target type | +| PathVariable | Path variable | @Param(type=PathVariable) | @PathVariable | @PathParam | Single-value array or collection | Single-value Map | +| MatrixVariable | Matrix variable | @Param(type=MatrixVariable) | @MatrixVariable | @MatrixParam | Multi-value | Single-value Map | +| Bean | Java Bean | No annotation needed | @ModelAttribute | @BeanParam | Attempts to parse as Bean array or collection | - | + + + +#### Special Parameter Types + +| Type | Description | Activation Condition | +|-------------------------------------------------|--------------------------------|--------------------------| +| `org.apache.dubbo.remoting.http12.HttpRequest` | HttpRequest object | Activated by default | +| `org.apache.dubbo.remoting.http12.HttpResponse` | HttpResponse object | Activated by default | +| `org.apache.dubbo.remoting.http12.HttpMethods` | HTTP request method | Activated by default | +| `java.util.Locale` | Request Locale | Activated by default | +| `java.io.InputStream` | Request InputStream | Activated by default | +| `java.io.OutputStream` | Response OutputStream | Activated by default | +| `javax.servlet.http.HttpServletRequest` | Servlet HttpRequest object | Requires Servlet API jar | +| `javax.servlet.http.HttpServletResponse` | Servlet HttpResponse object | Same as above | +| `javax.servlet.http.HttpSession` | Servlet HttpSession object | Same as above | +| `javax.servlet.http.Cookie` | Servlet Cookie object | Same as above | +| `java.io.Reader` | Servlet Request Reader object | Same as above | +| `java.io.Writer` | Servlet Response Writer object | Same 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: + +```java +// 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](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java#L40) + + +### 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](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java). +Custom parameter type conversion can also be achieved by implementing 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 | + + + +### 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 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 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](#NLQqj) + + +### 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: + +```java +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: + +```java +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 + + + +### Exception Handling + +Unhandled exceptions are ultimately converted to the `ErrorResponse` class and encoded for output: + +```java + +@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](#zFD9A) 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](https://github.com/apache/dubbo-samples/tree/master/2-advanced/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 Name | Description | Default Behavior | +|-------------|----------------------------------------------------------------------------------------|------------------------------------| +| `value` | Mapped URL paths, which can be one or more paths. | Empty array | +| `path` | Mapped URL paths, same as `value`, can be one or more paths. | Empty array | +| `method` | Supported HTTP methods list, such as `GET`, `POST`, etc. | Empty array (supports all methods) | +| `params` | List of parameters that must be included in the request. | Empty array | +| `headers` | List of headers that must be included in the request. | Empty array | +| `consumes` | Content types (Content-Type) for processing requests, which can be one or more types. | Empty array | +| `produces` | Content types (Content-Type) for generating responses, which can be one or more types. | Empty array | +| `enabled` | Whether 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](#kmCzf) + + + +#### Parameters Without Annotations + +Basic supports parameters without annotations through the +class: [FallbackArgumentResolver.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java#L41). +The detailed processing flow is as follows:
![rest-arg.jpg](/imgs/v3/manual/java/protocol/rest-arg.jpg) + + +## SpringMVC Usage Guide + +See +example: [dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc](https://github.com/apache/dubbo-samples/tree/master/2-advanced/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](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates)
+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](#kmCzf) + + +#### Annotated Parameter Types + +See [3.2.1 Annotated Parameter Types](#dCgzz) + + +#### Special Parameter Types + +| Type | Description | Activation Condition | +|----------------------------------------------------------|-------------------------|-------------------------------| +| org.springframework.web.context.request.WebRequest | WebRequest object | SpringWeb dependency required | +| org.springframework.web.context.request.NativeWebRequest | NativeWebRequest object | Same as above | +| org.springframework.http.HttpEntity | Http entity | Same as above | +| org.springframework.http.HttpHeaders | Http headers | Same as above | +| org.springframework.util.MultiValueMap | Multi-value map | Same as above | + + + +#### Parameters Without Annotations + +- For basic types (as determined + by [TypeUtils#isSimpleProperty](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java#L105)), + directly obtained from Parameter +- For non-basic types, + use [@ModelAttribute :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.html) to bind complex + bean type parameters + + +### 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](#I56vX) + + +### Exception Handling + +In addition to supporting the methods mentioned in [3.8 Exception Handling](#XeDPr), Spring's `@ExceptionHandler` annotation method is also +supported, [Exceptions :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-exceptionhandler.html). 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](#NLQqj), Spring's `@CrossOrigin` allows for fine-grained +configuration, [CORS :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc-cors.html#mvc-cors-controller). + + +### Custom HTTP Output + +Supports the following Spring customization methods: + +1. Use `@ResponseStatus` annotation +2. Return `org.springframework.http.ResponseEntity` object + + +### Supported Extensions + +- org.springframework.web.servlet.HandlerInterceptor
Usage is similar to [7.1 Using Filter Extensions](#xCEi3) + + +## JAX-RS Usage Guide + +See +example: [dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs](https://github.com/apache/dubbo-samples/tree/master/2-advanced/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](https://docs.jboss.org/resteasy/docs/6.2.7.Final/userguide/html/ch04.html) + + +### Parameter Types + + + +#### General Parameters + +See: [3.2 Parameter Types](#kmCzf) + + +#### Annotation Type Parameters + +| Annotation | Parameter Location | Description | +|---------------|--------------------|----------------------------------------| +| @QueryParam | querystring | Parameters corresponding to ?a=a&b=b | +| @HeaderParam | header | | +| @PathParam | path | | +| @FormParam | form | body in key1=value2&key2=value2 format | +| No annotation | body | Not explicitly annotated | + + + +#### Special Type Parameters + +| Type | Description | Activation Condition | +|---------------------------------|-----------------|----------------------------| +| javax.ws.rs.core.Cookie | Cookie object | Requires Jax-rs dependency | +| javax.ws.rs.core.Form | Form object | Same as above | +| javax.ws.rs.core.HttpHeaders | Http headers | Same as above | +| javax.ws.rs.core.MediaType | Media type | Same as above | +| javax.ws.rs.core.MultivaluedMap | Multivalued Map | Same as above | +| javax.ws.rs.core.UriInfo | Uri information | Same as above | + + + +#### Non-Annotated Parameters + +- For basic types (as determined + by [TypeUtils#isSimpleProperty](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java#L105)), + 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](#NLQqj) 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 + +```java +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` interface and `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension` interface, then register SPI + +```java +public class DemoFilter implements Supplier, 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 + +```java +public class DemoFilter implements Supplier, 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 + + +## 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 Name | Description | Default Value | +|-----------------------------------------------------|----------------------------------------------------------------------------------------------------|------------------------------------------| +| `dubbo.protocol.triple.rest.cors.allowed-origins` | List 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-methods` | List of allowed HTTP methods, e.g., `GET`, `POST`, `PUT`, `*` for all methods. | Not set (only `GET` and `HEAD`) | +| `dubbo.protocol.triple.rest.cors.allowed-headers` | List of allowed request headers in preflight requests, `*` for all headers. | Not set | +| `dubbo.protocol.triple.rest.cors.exposed-headers` | List of response headers exposed to clients, `*` for all headers. | Not set | +| `dubbo.protocol.triple.rest.cors.allow-credentials` | Whether user credentials are supported. | Not set (user credentials not supported) | +| `dubbo.protocol.triple.rest.cors.max-age` | Time (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` + +```java +public interface ExceptionHandler { + /** + * 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 + +```yaml +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 + +```yaml +dubbo: + protocol: + triple: + verbose: true +``` + +Enable verbose output will return internal error stack traces to the caller and output more error logs for troubleshooting. diff --git a/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md index d8cf5a233f33..1557c5c89802 100644 --- a/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md +++ b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md @@ -7,7 +7,7 @@ description: 在 Dubbo 中配置多协议 linkTitle: 多协议 title: 多协议 type: docs -weight: 5 +weight: 4 --- 区别于普通的 RPC 框架,Dubbo 作为一款微服务框架提供了非常灵活的协议支持,它不绑定一个单一通信协议。因此你**可以发布在一个进程中同时发布多个 RPC 协议、调用不同的 RPC 协议**。接下来我们就详细介绍多协议的具体使用场景与使用方式。 diff --git a/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/http.md b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak similarity index 100% rename from content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/http.md rename to content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak diff --git a/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md index 8dee0486f370..025ecc665590 100644 --- a/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md +++ b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md @@ -10,6 +10,10 @@ type: docs weight: 6 --- +{{% alert title="注意" color="warning" %}} +从 Dubbo 3.3 版本开始,Rest 协议已移至 Extensions 库,由 Triple 协议来对 Rest 提供更全面的支持,具体参见 [Triple Rest用户手册](../../tripe-rest-manual/), +如需继续使用原 Rest 协议,可引入对应 [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) 库依赖 +{{% /alert %}} 更加轻量,具有dubbo风格的rest,微服务体系互通(Springcloud Alibaba) diff --git a/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/rest.md.ba b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak similarity index 100% rename from content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/rest.md.ba rename to content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak diff --git a/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-3.3.md b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-3.3.md new file mode 100644 index 000000000000..f2edbb19c4f2 --- /dev/null +++ b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-3.3.md @@ -0,0 +1,276 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/3.3/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/3.3/ +description: "本文介绍 triple 协议在 3.3 版本中的新特性" +linkTitle: tripe-3.3新特性 +title: tripe-3.3新特性 +type: docs +weight: 5 +--- + + + +## 全新的 Rest 支持 + + + +### 特性 + +在3.3版本中,基于现有 HTTP 协议栈,triple实现了全面的 REST 风格服务导出能力,无需使用泛化或网关层协议转换,无需配置,用户即可通过 HTTP 协议去中心化直接访问后端的 Triple 协议服务。同时,针对高级 +REST 用法,如路径定制、输出格式定制和异常处理,提供了丰富的注解和 +SPI 扩展支持。其主要特性包括: + +- **Triple协议融合** + 重用Triple原有HTTP协议栈, 无需额外配置或新增端口,即可同时支持 HTTP/1、HTTP/2 和 HTTP/3 协议的访问。 +- **去中心化** + 可直接对外暴露 Rest API,不再依赖网关应用进行流量转发,从而提升性能,并降低因网关引发的稳定性风险。安全问题可通过应用内部扩展解决,这一实践已在淘宝内部的 MTOP 中得到验证。 +- **支持已有servlet设施** + 支持 Servlet API 和 Filter,用户可以重用现有基于 Servlet API 的安全组件。通过实现一个 Servlet Filter,即可集成 OAuth 和 Spring Security 等安全框架。 +- **多种方言** + 考虑到大部分用户习惯使用 SpringMVC 或 JAX-RS 进行 REST API 开发,Triple Rest 允许继续沿用这些方式定义服务,并支持大部分扩展和异常处理机制(具备原框架 80% 以上的功能)。对于追求轻量级的用户,可使用 + Basic 方言,Triple 的开箱即用 + REST 访问能力即基于此方言导出服务。 +- **扩展能力强** + 提供超过 20 个 扩展点,用户不仅可以轻松实现自定义方言,还能灵活定制参数获取、类型转换、错误处理等逻辑。 +- **开箱即用** + REST 能力开箱即用,只需启用 Triple 协议,即具备 REST 直接访问服务能力。 +- **高性能路由** + 路由部分采用优化的 [Radix Tree](https://github.com/apache/dubbo/blob/3.3/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java) 和 + Zero Copy 技术,提升路由性能。 +- **OpenAPI无缝集成(TBD)** + 即将完成 OpenAPI 集成,开箱即用支持导出 OpenAPI Schema, 引入 Swagger 依赖可直接使用 Web UI 来进行服务测试。有了 OpenAPI Schema + 可使用 [Postman](https://www.postman.com/)、[Apifox](https://apifox.com/) 等API工具来管理和测试 + API,利用 OpenAPI 生态可轻松实现跨语言调用。未来会进一步支持 Schema First 的方式,先和前端团队一起定义 OpenAPI, 前端基于 OpenAPI 来生成调用代码和 Mock,后端基于 OpenAPI 来生成 Stub + 来开发服务,极大提升协同效率。 + + +### 示例 + + + +###### 示例代码 + +```java +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; +} +``` + + + +###### 下载运行示例 + +```bash +# 获取示例代码 +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 +``` + + + +###### curl测试 + +```bash +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 +#> +#< HTTP/1.1 200 OK +#< content-type: application/json +#< 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 +#> c: 3 +#> Content-Length: 9 +#> Content-Type: application/x-www-form-urlencoded +#> +#< HTTP/1.1 200 OK +#< content-type: text/plain +#< content-length: 17 +#< +#Hello Mr. Yang, 3 +# +# 代码讲解 +# 可以看到输出 Hello Mr. Yang, 3 ,没有双引号是因为通过指定后缀 txt 的方式要求用 text/plain 输出 + #通过这个例子可以了解如何通过 Mapping 注解来定制路径,通过 Param 注解来定制参数来源,并支持通过 post body 或 url方式传递参数 +``` + + + +### 详情文档 + +请访问用户手册:[Tripe Rest Manual](../tripe-rest-manual/) + + +## 支持Servlet接入 + +在3.3版本中,可复用Spring Boot已有servlet监听端口来接入 HTTP 流量, 无需Netty监听新端口,简化部署,降低维护成本。通过减少对外部端口的依赖,有助于轻松通过企业防火墙和网关,简化网络部署,增强企业级应用的可维护性和安全性。 + + +### 示例 + + + +###### 下载运行示例 + +```bash +# 获取样例代码 +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-servlet +# 直接运行 +mvn spring-boot:run +``` + + + +###### curl测试 + +```shell +curl --http2-prior-knowledge -v 'http://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world' +# 输出如下 +#* [HTTP/2] [1] OPENED stream for http://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world +#* [HTTP/2] [1] [:method: GET] +#* [HTTP/2] [1] [:scheme: http] +#* [HTTP/2] [1] [:authority: localhost:50052] +#* [HTTP/2] [1] [:path: /org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world] +#> +#* Request completely sent off +#< HTTP/2 200 +#< content-type: application/json +#< date: Sun, 25 Aug 2024 03:38:12 GMT +#< +#"Hello world" +``` + + + +### 详情文档 + +请访问:[how-to-enable-servlet-support-for-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-servlet#how-to-enable-servlet-support-for-triple) +了解如何配置并启用 servlet 支持 + + +## 支持HTTP/3协议 + + + +### 特性 + +在3.3版本中,triple实现了对HTTP/3协议的支持,rpc 请求和 rest 请求均可通过 HTTP/3 协议传输,使用 HTTP/3 可以带来一下好处: + +- **提升性能** + 支持 HTTP/3 后,利用 QUIC 协议降低延迟,加快请求响应速度,特别是在高延迟或复杂网络环境中,能够显著提升服务的整体性能。 +- **增强可靠性** + HTTP/3 通过多路复用和连接迁移避免队头阻塞,即使在网络状况不佳时,也能保持连接的稳定性,确保服务的可靠交付。 +- **提高安全性** + HTTP/3 强制要求 TLS1.3 加密,相比传统HTTP/2 可选加密,提供了更安全的通信保障。 +- **适应弱网络环境** + 在高丢包率或带宽不稳定的情况下,HTTP/3 能够维持较高地连接质量和服务性能,提升在弱网络环境中的性能。 + +由于 HTTP/3 基于 QUIC 协议(UDP),可能会被防火墙或网关阻止。因此,triple 实现了 HTTP/3 协商能力并默认启用。连接首先通过 HTTP/2 建立,如果成功且服务端返回表示支持 HTTP/3 +的[Alt-Svc](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc) 头,客户端将自动切换到HTTP/3 + + +### 示例 + + + +###### 下载运行示例 + +```bash +# 获取样例代码 +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-http3 +# 直接运行 +mvn spring-boot:run +``` + + + +###### curl测试 + +请注意,curl 需要升级到支持 HTTP/3 的新版本, 参见:[https://curl.se/docs/http3.html](https://curl.se/docs/http3.html) + +```shell + +curl --http3 -vk 'https://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world' +# 输出如下 +#* QUIC cipher selection: TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256 +#* Skipped certificate verification +#* using HTTP/3 +#* [HTTP/3] [0] OPENED stream for https://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world +#* [HTTP/3] [0] [:method: GET] +#* [HTTP/3] [0] [:scheme: https] +#* [HTTP/3] [0] [:authority: localhost:50052] +#* [HTTP/3] [0] [:path: /org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world] +#> +#* Request completely sent off +#< HTTP/3 200 +#< content-type: application/json +#< +#"Hello world" +``` + + + +### 性能对比 + +#### 丢包率对 QPS 的影响 + +![http3-qps.jpg](/imgs/v3/manual/java/protocol/http3-qps.jpg) + +#### 丢包率对 RT 的影响 + +![http3-rt.jpg](/imgs/v3/manual/java/protocol/http3-rt.jpg) + + + +### 架构图 + +![http3-arch.jpg](/imgs/v3/manual/java/protocol/http3-arch.jpg) + +### 详情文档 + +请访问:[how-to-enable-http3-support-for-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-http3#how-to-enable-http3-support-for-triple) +了解如何配置并启用 HTTP/3 支持 diff --git a/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md new file mode 100644 index 000000000000..0fd94c0c270e --- /dev/null +++ b/content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md @@ -0,0 +1,920 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/rest/manual/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/rest/manual/ +description: "本文是Triple Rest的用户使用手册" +linkTitle: triple-rest用户手册 +title: triple-rest用户手册 +type: docs +weight: 7 +--- + +{{% alert title="注意" color="warning" %}} +从 Dubbo 3.3 版本开始,原 Rest 协议已移至 Extensions 库,由 Triple 协议来对 Rest 提供更全面的支持,如需继续使用原 Rest 协议, +可引入对应 [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) 库依赖 +{{% /alert %}} + +## 前言 + +从 Dubbo 3.3 版本开始,Triple 协议重用已有的 HTTP 协议栈,实现了全面的 REST 风格服务导出能力。无需使用泛化或网关层协议转换,无需配置,用户即可通过 HTTP 协议去中心化直接访问后端的 Triple +协议服务。同时,针对高级 REST 用法,如路径定制、输出格式定制和异常处理,提供了丰富的注解和 +SPI 扩展支持。其主要特性包括: + +- **Triple协议融合** + 重用Triple原有HTTP协议栈, 无需额外配置或新增端口,即可同时支持 HTTP/1、HTTP/2 和 HTTP/3 协议的访问。 +- **去中心化** + 可直接对外暴露 Rest API,不再依赖网关应用进行流量转发,从而提升性能,并降低因网关引发的稳定性风险。安全问题可通过应用内部扩展解决,这一实践已在淘宝内部的 MTOP 中得到验证。 +- **支持已有servlet设施** + 支持 Servlet API 和 Filter,用户可以重用现有基于 Servlet API 的安全组件。通过实现一个 Servlet Filter,即可集成 OAuth 和 Spring Security 等安全框架。 +- **多种方言** + 考虑到大部分用户习惯使用 SpringMVC 或 JAX-RS 进行 REST API 开发,Triple Rest 允许继续沿用这些方式定义服务,并支持大部分扩展和异常处理机制(具备原框架 80% 以上的功能)。对于追求轻量级的用户,可使用 + Basic 方言,Triple 的开箱即用 + REST 访问能力即基于此方言导出服务。 +- **扩展能力强** + 提供超过 20 个 扩展点,用户不仅可以轻松实现自定义方言,还能灵活定制参数获取、类型转换、错误处理等逻辑。 +- **开箱即用** + REST 能力开箱即用,只需启用 Triple 协议,即具备 REST 直接访问服务能力。 +- **高性能路由** + 路由部分采用优化的 [Radix Tree](https://github.com/apache/dubbo/blob/3.3/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java) 和 + Zero Copy 技术,提升路由性能。 +- **OpenAPI无缝集成(TBD)** + 即将完成 OpenAPI 集成,开箱即用支持导出 OpenAPI Schema, 引入 Swagger 依赖可直接使用 Web UI 来进行服务测试。有了 OpenAPI Schema + 可使用 [Postman](https://www.postman.com/)、[Apifox](https://apifox.com/) 等API工具来管理和测试 + API,利用 OpenAPI 生态可轻松实现跨语言调用。未来会进一步支持 Schema First 的方式,先和前端团队一起定义 OpenAPI, 前端基于 OpenAPI 来生成调用代码和 Mock,后端基于 OpenAPI 来生成 Stub + 来开发服务,极大提升协同效率。 + + +## 快速开始 + +让我们从一个简单的例子开始了解 Triple Rest。您可以直接下载已有的示例项目以快速上手,假设您已经安装好 Java、Maven 和 Git + + +### 下载并运行示例 + +```bash +# 获取示例代码 +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 的方式来深入理解原理。 + + +### 示例代码 + +```java +// 服务接口 +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; +} +``` + + + +### 测试基本服务 + +```bash +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方式传递参数 + + +### 测试高级服务 + +```bash +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使用指南](#GdlnC) + + +### 观察日志 + +可以通过打开 debug 日志的方式来了解rest的启动和响应请求过程 + +```yaml +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 的映射方式,相关文档: + +- [Spring Mapping Requests](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates) +- [Spring PathPattern](https://docs.spring.io/spring-framework/docs/6.1.12/javadoc-api/org/springframework/web/util/pattern/PathPattern.html) +- [Spring AntPathMatcher](https://docs.spring.io/spring-framework/docs/6.1.12/javadoc-api/org/springframework/util/AntPathMatcher.html) +- [JAX-RS Path and regular expression mappings](https://docs.jboss.org/resteasy/docs/6.2.7.Final/userguide/html/ch04.html) + +还支持通过实现 SPI `org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver` 来自定义路径映射 + + +#### 支持的模式 + +1. `books` 字符串常量,最基本的类型,匹配一个固定的段 +2. `?` 匹配一个字符 +3. `*` 匹配路径段中的零个或多个字符 +4. `**` 匹配直到路径末尾的零个或多个路径段 +5. `{spring}` 匹配一个路径段并将其捕获为名为 "spring" 的变量 +6. `{spring:[a-z]+}` 使用正则表达式 `[a-z]+` 匹配路径段,并将其捕获为名为 "spring" 的路径变量 +7. `{*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](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java#L196) [RequestMapping.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java#L127) + +1. 使用 `PathUtils.normalize` 对路径进行清洗,去掉诸如 `/one/../` `/one/./` 之类间接路径,保证一定已 `/` 开头 +2. 检查 `http method` 是否匹配 +3. 检查 `path` 是否匹配 +4. 检查 `paramter` 是否匹配(JAX-RS不支持) +5. 检查 `header` 是否匹配 +6. 检查 `content-type` 是否匹配(Consumes) +7. 检查 `accept` 是否匹配 (Produces) +8. 检查 `serviceGroup` 和 `serviceVersion` 是否匹配 +9. 检查 `method` 首字母签名是否匹配 +10. 未找到任何匹配项,如果尾 `/` 匹配开启并且路径 `/` 结尾则去掉尾 `/` 尝试从第2步开始匹配 +11. 未找到任何匹配项,如果扩展名匹配开启并且扩展名被支持,则去掉扩展名尝试从第2步开始匹配 +12. 如果最后一段路径包含 `~` 表示开启 method 首字母签名匹配,尝试从第2步开始匹配 +13. 如果候选项为0,匹配结束,返回null +14. 如果候选项为0,匹配结束,返回命中项 +15. 如果不止一个候选项,对候选项进行排序 +16. 对第一项和第二项进行顺序比较 +17. 结果为0表示无法确认最终匹配项,抛异常失败 +18. 第一项胜出,匹配结束,返回命中项 + + +#### 路径重复问题 + +与 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对象 | 同上 | + + + +#### 无注解参数 + +不同方言处理方式不同,请参见各方言使用说明 + + +#### 无入参方式获取 HTTP 输入输出参数 + +可通过 `RpcContext` 来获取 + +```java +// 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](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java#L40) + + +### 参数类型转换 + +默认支持大部分从 String 到目标类型的参数类型转换,主要包括以下几大类: + +- Jdk内置类型,包括基础类型和日期、Optional等 +- 数组类型 +- 集合类型 +- Map类型 + +同时也完整支持泛型类型,包括复杂嵌套,具体地实现代码参见: [GeneralTypeConverter.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/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 + +默认支持以下 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,具体流程如下: + +1. 尝试读取 Mapping 指定的 mediaType,获取 Produces指定的 mediaType 列表,并将通配符匹配到合适的 Media Type。例如Spring的: + `@RequestMapping(produces = "application/json")` +2. 尝试通过 Accept 头查找 mediaType,解析请求的 `Accept` 头,并将通配符匹配到合适的 Media Type。例如: + `Accept: application/json` +3. 尝试通过 format 参数查找 mediaType,读取 format 参数值,做为文件后缀匹配到合适的 Media Type。例如 `/hello?format=yml` +4. 尝试通过请求路径的扩展名查找 mediaType,扩展名做为文件后缀匹配到合适的 Media Type。例如 `/hello.txt` +5. 尝试读取请求的 Content-Type 头做为 Media Type(两种form类型除外)。例如 `Content-Type: application/json` +6. 使用 `application/json` 兜底 + + +### CORS支持 + +提供完整的CORS支持,通过配置全局参数即可启用,默认行为和SpringMVC一致,同时在SpringMVC方言中,也支持通过 +`@CrossOrigin` 来做精细化配置。
支持的CORS 配置项参见:[8.4CORS配置](#NLQqj) + + +### 自定义HTTP输出 + +很多场景需要对HTTP输出进行定制,比如做302跳转,写Http头,为此 Triple Rest提供以下通用方案,同时也支持各方言的特定写法,详情参见各方言使用指南 + +- 返回值设置为: `org.apache.dubbo.remoting.http12.HttpResult` 可通过 `HttpResult#builder` 来构建 +- 抛出Payload异常: + `throws new org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException(HttpResult)` 示例代码: + +```java +throw new HttpResult.found("https://a.com"). + +toPayload(); +``` + +此异常已避免填充错误栈,对性能无太大影响,并且不用考虑返回值逻辑,推荐用这个方式来定制输出 + +- 获取 HttpResponse 后自定义,实例代码: + +```java +HttpResponse response = RpcContext.getServiceContext().getRequest(HttpResponse.class); + +response. + +sendRedirect("https://a.com"); +response. + +setStatus(404); +response. + +outputStream(). + +write(data); +// 写完输出建议 commit 来避免被其他扩展改写 +response. + +commit(); +``` + +如果只是增加 `http header` 推荐用这个方式 + + +### 自定义JSON序列化 + + + +### 异常处理 + +未被处理的异常最终被转换成 `ErrorResponse` 类编码后输出: + +```java + +@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` 方法。
提供了以下通用方法来定制异常处理: + +- 参考 [9.2自定义异常返回结果](#zFD9A) 使用SPI 自定义全局异常处理 +- 使用 Dubbo的 Filter SPI 来加工转换异常,如果需要访问 Http 上下文,可继承 `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter` +- 使用 SPI `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter` 来转换异常,使用上更轻量并提供路径匹配配置能力 + +注意后2项只能拦截 invoke 链中出现的异常,如果在路径匹配阶段出现异常,只有有方法1能处理 + + +## Basic使用指南 + +示例参见:[dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic](https://github.com/apache/dubbo-samples/tree/master/2-advanced/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`(启用) | + +- 属性支持用占位符方式配置:`@Mapping("${prefix}/hi")` +- 如果不希望特定服务或方法被 rest 导出,可以通过设置 `@Mapping(enabled = false)` 解决 + + +### 入参类型 + +通用入参见:[3.2入参类型](#kmCzf) + + +#### 无注解参数 + +Basic +的无注解参数由类:[FallbackArgumentResolver.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java#L41) +支持,具体处理流程如下:
![rest-arg.jpg](/imgs/v3/manual/java/protocol/rest-arg.jpg) + + +## SpringMVC使用指南 + +示例参见:[dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc) + + +### 路径映射 + +直接参考SpringMVC文档即可,支持绝大多数特性,[Mapping Requests :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates)
+注意无需 +`@Controller` 或 `@RestController` 注解,除了 `@RequestMapping` 还支持新的 `@HttpExchange` + + +### 入参类型 + + + +#### 通用入参 + +参见:[3.2入参类型](#kmCzf) + + +#### 注解类型参数 + +参见 [3.2.1通用类型参数](#dCgzz) + + +#### 特殊类型参数 + +| 类型 | 说明 | 激活条件 | +|----------------------------------------------------------|--------------------|---------------| +| 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 | 同上 | + + + +#### 无注解参数 + +- 如果是基本类型 ( + 根据 [TypeUtils#isSimpleProperty](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java#L105) + 判断),直接从Parameter中获取 +- 如果非基本类型,使用 [@ModelAttribute :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.html) + 来绑定复杂 bean 类型参数 + + +### 参数类型转换 + +优先使用 Spring 的 `org.springframework.core.convert.ConversionService` 来转换参数,如果应用为spring boot应用则默认使用 +`mvcConversionService` 否则使用 +`org.springframework.core.convert.support.DefaultConversionService#getSharedInstance` 获取共享 +`ConversionService`
如果 `ConversionService` 不支持则会回退到通用类型转换:[3.3参数类型转换](#I56vX) + + +### 异常处理 + +除了支持 [3.8异常处理](#XeDPr) 中提到的方式,还支持 Spring +`@ExceptionHandler` 注解方式,[Exceptions :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-exceptionhandler.html) +,注意通过这种方式仅能处理方法调用时抛出的异常,其他异常无法捕获 + + +### CORS配置 + +除了支持 [8.4CORS配置](#NLQqj) 全局配置,还支持 Spring +`@CrossOrigin` 来精细化配置,[CORS :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc-cors.html#mvc-cors-controller) + + +### 自定义HTTP输出 + +支持以下 Spring 自定义方式: + +1. 使用 `@ResponseStatus` 注解 +2. 返回 `org.springframework.http.ResponseEntity` 对象 + + +### 支持的扩展 + +- org.springframework.web.servlet.HandlerInterceptor
使用方式类似 [7.1使用 Filter 扩展](#xCEi3) + + +## JAX-RS使用指南 + +示例参见:[dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs) + + +### 路径映射 + +Service需要显式添加注解@Path,方法需要添加@GET、@POST、@HEAD等请求方法注解
+直接参考Resteasy文档即可,支持绝大多数特性,[Chapter 4. Using @Path and @GET, @POST, etc](https://docs.jboss.org/resteasy/docs/6.2.7.Final/userguide/html/ch04.html) + + +### 入参类型 + + + +#### 通用入参 + +参见:[3.2入参类型](#kmCzf) + + +#### 注解类型参数 + +| 注解 | 参数位置 | 说明 | +|--------------|-------------|--------------------------------| +| @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信息 | 同上 | + + + +#### 无注解参数 + +- 如果是基本类型 ( + 根据 [TypeUtils#isSimpleProperty](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java#L105) + 判断),直接从Parameter中获取 +- 如果非基本类型, 将其视为请求体 (body)来解码对象 + + +### 参数类型转换 + +可通过扩展自定义参数转换,扩展接口: + +``` +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 +``` + + + +### CORS配置 + +支持 [8.4CORS配置](#NLQqj) 全局配置 + + +### 自定义HTTP输出 + +支持以下 Jaxrs 自定义方式: + +- 返回 `javax.ws.rs.core.Response` 对象 + + +### 支持的扩展 + +1. javax.ws.rs.container.ContainerRequestFilter
请求过滤器,允许在请求到达资源方法之前对请求进行预处理。 +2. javax.ws.rs.container.ContainerResponseFilter
响应过滤器,允许在响应离开资源方法之后对响应进行后处理。 +3. javax.ws.rs.ext.ExceptionMapper
异常映射器,将抛出的异常映射为HTTP响应。 +4. javax.ws.rs.ext.ParamConverterProvider
参数转换器,允许将请求参数转换为资源方法的参数类型。 +5. javax.ws.rs.ext.ReaderInterceptor
读取拦截器,允许在读取请求实体时进行拦截和处理。 +6. javax.ws.rs.ext.WriterInterceptor
写入拦截器,允许在写入响应实体时进行拦截和处理。 + + +## Servlet使用指南 + +同时低版本javax和高版本jakarta servlet API,jakarta API 优先级更高,只需要引入jar即可使用HttpServletRequest和HttpServletResponse作为参数 + + +### 使用 Filter 扩展 + +方法1,实现 `Filter` 接口和 `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension` 接口,然后注册SPI + +```java +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` 接口和 `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension` 接口,然后注册SPI + +```java +public class DemoFilter implements Supplier, RestExtension { + + private final Filter filter = new SsoFilter(); + + @Override + public Filter get() { + return filter; + } +} +``` + +这种方式对于重用已有 Filter 非常方便,甚至可以从 Spring Context 中获取 Filter 实例并注册 + +```java +public class DemoFilter implements Supplier, 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支持 + +实现 SPI `org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory` + + +### 尚不支持的特性 + +- Filter 中 wrap request 和 response对象不会生效,原因是 Rest支持的 过滤器种类很多,使用wrapper会导致反复嵌套,处理过于复杂 +- 不支持 `request.getRequestDispatcher` + + +## 全局参数配置 + + + +### 大小写敏感 + +配置名:`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` + + +### CORS配置 + +| 配置名 | 说明 | 默认值 | +|-----------------------------------------------------|-------------------------------------------------------|-------------------------| +| `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` | 预检请求的响应可以被客户端缓存的时间(以秒为单位)。 | 未设置 | + + + +## 高级使用指南 + + + +### 支持的扩展点汇总 + +1. javax.servlet.Filter
Servlet API过滤器。 +2. org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory
用于在Servlet API中支持 HttpSession。 +3. javax.ws.rs.container.ContainerRequestFilter
用于在JAX-RS中实现请求过滤器,允许在请求到达资源方法之前对请求进行预处理。 +4. javax.ws.rs.container.ContainerResponseFilter
用于在JAX-RS中实现响应过滤器,允许在响应离开资源方法之后对响应进行后处理。 +5. javax.ws.rs.ext.ExceptionMapper
用于在JAX-RS中实现异常映射器,将抛出的异常映射为HTTP响应。 +6. javax.ws.rs.ext.ParamConverterProvider
用于在JAX-RS中提供参数转换器,允许将请求参数转换为资源方法的参数类型。 +7. javax.ws.rs.ext.ReaderInterceptor
用于在JAX-RS中实现读取拦截器,允许在读取请求实体时进行拦截和处理。 +8. javax.ws.rs.ext.WriterInterceptor
用于在JAX-RS中实现写入拦截器,允许在写入响应实体时进行拦截和处理。 +9. org.springframework.web.servlet.HandlerInterceptor
用于在Spring MVC中实现处理器拦截器。 +10. org.apache.dubbo.remoting.http12.ExceptionHandler
提供异常自定义处理机制。 +11. org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory
提供HTTP消息的适配和转换功能。 +12. org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
提供HTTP消息的解码功能。 +13. org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
提供HTTP消息的编码功能。 +14. org.apache.dubbo.rpc.HeaderFilter
用于在Dubbo RPC中实现头部过滤器,允许对请求和响应的头部进行过滤和处理。 +15. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestHeaderFilterAdapter
头部过滤器适配器,提供访问http输入输出能力。 +16. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter
Dubbo Filter Rest适配器,提供访问http输入输出能力。 +17. org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping
用于在Dubbo Triple中实现请求映射能力。 +18. org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver
用于解析REST请求映射。 +19. org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit
提供REST相关的工具和实用程序。 +20. org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter
提供参数的类型转换功能。 +21. org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver
提供参数的解析功能。 +22. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter
提供REST请求和响应的过滤功能。 +23. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter
提供RestExtension的adapt能力,将已有filter接口映射到RestFilter接口。 + + +### 自定义异常返回结果 + +通过 SPI `org.apache.dubbo.remoting.http12.ExceptionHandler` 来自定义异常处理逻辑 + +```java +public interface ExceptionHandler { + /** + * 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 指定为需要处理的异常类型 + +- resolveLogLevel
Dubbo框架内部会打印Rest处理异常日志,可以通过实现这个方法来自定义需要打印的日志级别或忽略日志。 +- handle
如果返回结果不是 null ,则将直接输出返回结果,可以通过返回 + `org.apache.dubbo.remoting.http12.HttpResult` 来定制输出的 headers 和 status code。 + + +### 打开debug日志 + +```yaml +logging: + level: + "org.apache.dubbo.rpc.protocol.tri": debug + "org.apache.dubbo.remoting": debug +``` + +开启 debug 日志会输出详细的启动日志和请求响应日志,便于排查问题。 + + +### 打开verbose输出 + +```yaml +dubbo: + protocol: + triple: + verbose: true +``` + +开启 verbose 输出会将内部错误堆栈返回给调用方,并输出更多错误日志,便于排查问题。 diff --git a/content/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple.md b/content/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple.md index 4adcc6774821..ef5ebe542cf4 100644 --- a/content/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple.md +++ b/content/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple.md @@ -12,19 +12,20 @@ weight: 3 在 [triple协议规范](/zh-cn/overview/reference/protocols/triple-spec/) 中我们曾详细介绍了 triple 对于浏览器、网关的友好性设计,其中非常重要的一点是 triple 同时支持跑在 HTTP/1、HTTP/2 上: * 在后端服务之间使用高效的 triple 二进制协议。 -* 对于前端接入层,则支持所有标准 HTTP 工具如 cURL 等以标准 `application/json` 格式请求后端服务。 +* 对于前端接入层,则支持所有标准 HTTP 工具如 cURL 等以标准 `application/json` 、`application/yaml` 等格式请求后端服务。 接下来我们就看一下,对于前端 HTTP 流量而言,如何通过一些通用的网关产品快速接入后端的 triple 微服务体系。 {{% alert title="注意" color="warning" %}} 使用 triple 协议后,不再需要泛化调用、`http -> dubbo` 协议转换等步骤,任何主流的网关设备都可以通过 http 流量直接访问后端 triple 协议服务。 +具体参见 [发布 REST 风格的服务](../../protocols/rest/) {{% /alert %}} ## 原生 HTTP 接入 -如上图所示,从浏览器、手机或 Web 服务器过来的 HTTP 请求,网关可直接以 `application/json` 格式转发给后端 Dubbo 服务,后端服务之间则继续走 triple 二进制协议。**由于进出网关的都是标准的 HTTP 流量,网关不需要做任何的私有协议转换工作,不需要任何定制化逻辑,只需专注于流量路由等职责即可。** +如上图所示,从浏览器、手机或 Web 服务器过来的 HTTP 请求,网关可直接转发给后端 Dubbo 服务,后端服务之间则继续走 triple 二进制协议。**由于进出网关的都是标准的 HTTP 流量,网关不需要做任何的私有协议转换工作,不需要任何定制化逻辑,只需专注于流量路由等职责即可。** 在真正的生产环境下,**唯一需要网关解决的只剩下地址发现问题,即如何动态感知后端 triple 服务的实例变化?** 好消息是,目前几款主流的开源网关产品如 Apache APISIX、Higress 等普遍支持以 Nacos、Zookeeper、Kubernetes 作为 upstream 数据源。 diff --git a/content/zh-cn/overview/mannual/java-sdk/tasks/protocols/rest.md b/content/zh-cn/overview/mannual/java-sdk/tasks/protocols/rest.md index 10840233e48a..7a795bd8a5de 100644 --- a/content/zh-cn/overview/mannual/java-sdk/tasks/protocols/rest.md +++ b/content/zh-cn/overview/mannual/java-sdk/tasks/protocols/rest.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/protocols/ - - /zh-cn/overview/tasks/protocols/ + - /zh/overview/tasks/protocols/ + - /zh-cn/overview/tasks/protocols/ description: "演示了如何以标准 `rest` 请求访问 triple、dubbo 协议发布的服务。" hide: true linkTitle: rest协议 @@ -10,10 +10,14 @@ type: docs weight: 3 --- -**本文要讲的 "rest 协议" 实际上并不是一个真正的协议实现,而是关于如何使得 triple 协议支持以 rest 风格的 http 请求直接访问。** 我们将演示如何使用 rest 请求访问标准 triple 协议的 Dubbo 服务。 +{{% alert %}} +本文要讲的 "rest 协议" 实际上并不是一个真正的协议实现,而是关于如何使得 triple 协议支持以 rest 风格的 http 请求直接访问。 +我们将演示如何使用 rest 请求访问标准 triple 协议的 Dubbo 服务。 +{{% /alert %}} {{% alert title="注意" color="warning" %}} -自 Dubbo 3.3 版本之后,我们已经完全移除了老版本的 rest 协议实现,新版本的内置协议实现只剩下 triple 与 dubbo。因此,当我们提到 rest 时,都是指 triple 协议的 rest 访问支持能力。 +从 Dubbo 3.3 版本开始,rest 协议已移至 extensions 库,由 triple 协议来对 Rest 提供更全面的支持,新版本的内置协议实现只剩下 triple 和 dubbo。 +
因此,当我们提到 rest 时,都是指 triple 协议的 rest 访问支持能力,具体参见 [Triple Rest用户手册](../../../reference-manual/protocol/tripe-rest-manual/) {{% /alert %}} 在讲解 [triple 协议示例](../triple/interface/#curl) 时,我们曾提到 triple 协议支持以 `application/json` 格式直接访问: @@ -25,80 +29,150 @@ curl \ http://localhost:50052/org.apache.dubbo.samples.api.GreetingsService/sayHi/ ``` -如果你觉得以上 `http://localhost:50052/org.apache.dubbo.samples.api.GreetingsService/sayHi` 格式的 http 请求不够好,我们还可以让 triple 支持 rest 格式的 http 请求,只需要为接口增加一些注解即可 -- 目前支持 Spring Web、JAX-RS 两种注解格式。以下示例的完整代码请参见 [dubbo-samples-triple-rest](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest)。 +如果你认为以上 +`http://localhost:50052/org.apache.dubbo.samples.api.GreetingsService/sayHi` 格式的 path 请求不够友好,还可以通过注解自定义 http 请求的路径和方法等参数, +目前已支持 内置,Spring Web和JAX-RS 三种注解格式。以下示例的完整代码请参见 [dubbo-samples-triple-rest](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest)。 -## 运行示例 -你可以跟随以下步骤,尝试运行本文档对应的示例源码。 +### 下载并运行示例 -首先,可通过以下命令下载示例源码 -```shell +```bash +# 获取示例代码 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 ``` -进入示例源码目录: -```shell -cd dubbo-samples/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc -``` +当然,也可以直接用IDE导入工程后直接执行 +`org.apache.dubbo.rest.demo.BasicRestApplication#main` 来运行,并通过下断点 debug 的方式来深入理解原理。 + -使用 maven 打包示例: -```shell -mvn clean install -DskipTests -``` +### 示例代码 -### 启动server -运行以下命令启动提供者。 -```shell -java -jar ./provider/target/xxx.jar +```java +// 服务接口 +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; +} ``` -### 启动client -* cURL -* Dubbo Client - -```shell -curl + + +### 测试基本服务 + +```bash +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" ``` -运行以下命令 -```shell -java -jar ./consumer/target/xxx.jar +代码讲解:
可以看到输出了 "Hello world" ,有双引号是因为默认输出 content-type 为 application/json
通过这个例子可以了解 Triple 默认将服务导出到 +`/{serviceInterface}/{methodName}`路径,并支持通过url方式传递参数 + + +### 测试高级服务 + +```bash +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 ``` -## 源码讲解 -### 定义服务 -与开发 dubbo 协议一样,我们首先需要通过 Java Interface 定义服务,同时为接口增加注解 Spring Web 注解: -```java +代码讲解:
可以看到输出 Hello Mr. Yang, 3 ,没有双引号是因为通过指定后缀 txt 的方式要求用 `text/plain` 输出
通过这个例子可以了解如何通过 Mapping 注解来定制路径,通过 Param 注解来定制参数来源,并支持通过 post body 或 url方式传递参数,详细说明参见: [Basic使用指南](../../../reference-manual/protocol/tripe-rest-manual/#GdlnC) + -``` +### 观察日志 -### 服务实现 -服务的具体实现,与普通 dubbo 服务实现一样: -```java -``` +可以通过打开 debug 日志的方式来了解rest的启动和响应请求过程 -配置使用 `rest` 协议: ```yaml - +logging: + level: + "org.apache.dubbo.rpc.protocol.tri": debug + "org.apache.dubbo.remoting": debug ``` -### 服务消费者 - -配置服务引用,如下所示: -```java +打开后可以观察到 Rest 映射注册和请求响应过程 ``` - -接下来,就可以发起对远程服务的 RPC 调用了: -```java +# 注册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]} ``` -或者,你可以是用任何 HTTP 工具访问刚刚发布的服务。 - - ## 实际应用场景 + 接下来,我们看一下在 triple 协议支持 rest 格式访问后,能被应用于哪些场景中解决实际问题。 ### Spring Cloud 互调 + 首先,第一个场景就是实现 Dubbo 体系与 http 微服务体系互通。 设想你是一条业务线负责人,你们有一套基于 Dubbo 开发的微服务集群,集群内服务间都是基于 triple 二进制协议通信;公司内还有一个重要业务,是跑在基于 Spring Cloud 开发的微服务集群上,而 Spring Cloud 集群内的服务间都是 http+json 协议通信。现在要实现这两个业务的互通,服务之间如何实现互调那?triple 协议支持 rest 格式访问可以解决这个问题,对于 Dubbo 微服务集群而言,相当于是对内使用 triple 二进制协议通信,对外交互使用 triple 提供的 rest 请求格式。 @@ -107,7 +181,8 @@ java -jar ./consumer/target/xxx.jar ### 网关流量接入 -支持 rest 格式访问的另外一个非常有价值的场景就是方便网关流量接入。二进制格式的 rpc 协议接入一直是个难题,之前 dubbo 还特意提供了 `泛化调用` 来解决这个问题,网关可以基于泛化调用实现 `http -> dubbo` 协议转换来接入后端微服务集群。 +支持 rest 格式访问的另外一个非常有价值的场景就是方便网关流量接入。二进制格式的 rpc 协议接入一直是个难题,之前 dubbo 还特意提供了 +`泛化调用` 来解决这个问题,网关可以基于泛化调用实现 `http -> dubbo` 协议转换来接入后端微服务集群。 -现在,有了 rest 格式支持,我们有办法让接入变得更加简单。具体请参见 [HTTP 网关流量接入](../../gateway/) +现在,有了 rest 格式支持,无需任何网关做协议转换,即可实现去中心化接入。具体请参见 [HTTP 网关流量接入](../../gateway/) diff --git a/content/zh-cn/overview/reference/protocols/http.md b/content/zh-cn/overview/reference/protocols/http.md index 0da4d7b29d09..2c1c5b24b78d 100644 --- a/content/zh-cn/overview/reference/protocols/http.md +++ b/content/zh-cn/overview/reference/protocols/http.md @@ -7,6 +7,10 @@ weight: 3 working_in_progress: true --- +{{% alert title="注意" color="warning" %}} +从 Dubbo 3.3 版本开始,Rest 协议已移至 Extensions 库,由 Triple 协议来对 Rest 提供更全面的支持,具体参见 [Triple Rest用户手册](../../../mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/), +如需继续使用原 Rest 协议,可引入对应 [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) 库依赖 +{{% /alert %}} ## 什么是 Dubbo Http 基于 spring web 和 resteasy 注解编码风格,通过http协议进行服务间调用互通,dubbo protocol扩展实现的协议 diff --git a/static/imgs/v3/manual/java/protocol/http3-arch.jpg b/static/imgs/v3/manual/java/protocol/http3-arch.jpg new file mode 100644 index 000000000000..629b2103eccc Binary files /dev/null and b/static/imgs/v3/manual/java/protocol/http3-arch.jpg differ diff --git a/static/imgs/v3/manual/java/protocol/http3-qps.jpg b/static/imgs/v3/manual/java/protocol/http3-qps.jpg new file mode 100644 index 000000000000..9e70654208e1 Binary files /dev/null and b/static/imgs/v3/manual/java/protocol/http3-qps.jpg differ diff --git a/static/imgs/v3/manual/java/protocol/http3-rt.jpg b/static/imgs/v3/manual/java/protocol/http3-rt.jpg new file mode 100644 index 000000000000..0ad9aab8ef03 Binary files /dev/null and b/static/imgs/v3/manual/java/protocol/http3-rt.jpg differ diff --git a/static/imgs/v3/manual/java/protocol/rest-arg.jpg b/static/imgs/v3/manual/java/protocol/rest-arg.jpg new file mode 100644 index 000000000000..4bae0668224c Binary files /dev/null and b/static/imgs/v3/manual/java/protocol/rest-arg.jpg differ