From a87ad394813ac0fb2af73cea005fef96fa0ea7e9 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Mon, 26 Aug 2024 09:57:38 +0800 Subject: [PATCH] Rest docs (#3026) --- .../reference-manual/protocol/http.md | 5 + .../reference-manual/protocol/rest.md | 5 + .../reference-manual/protocol/tripe-3.3.md | 282 ++++++ .../protocol/tripe-rest-manual.md | 924 ++++++++++++++++++ .../protocol/multi-protocols.md | 2 +- .../protocol/others/{http.md => http.md.bak} | 0 .../others/v3.2_rest_protocol_design.md | 4 + .../protocol/{rest.md.ba => rest.md.bak} | 0 .../reference-manual/protocol/tripe-3.3.md | 276 ++++++ .../protocol/tripe-rest-manual.md | 920 +++++++++++++++++ .../mannual/java-sdk/tasks/gateway/triple.md | 5 +- .../mannual/java-sdk/tasks/protocols/rest.md | 181 +++- .../overview/reference/protocols/http.md | 4 + .../v3/manual/java/protocol/http3-arch.jpg | Bin 0 -> 136852 bytes .../v3/manual/java/protocol/http3-qps.jpg | Bin 0 -> 92227 bytes .../imgs/v3/manual/java/protocol/http3-rt.jpg | Bin 0 -> 80611 bytes .../imgs/v3/manual/java/protocol/rest-arg.jpg | Bin 0 -> 57283 bytes 17 files changed, 2552 insertions(+), 56 deletions(-) create mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-3.3.md create mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-rest-manual.md rename content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/others/{http.md => http.md.bak} (100%) rename content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/{rest.md.ba => rest.md.bak} (100%) create mode 100644 content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-3.3.md create mode 100644 content/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md create mode 100644 static/imgs/v3/manual/java/protocol/http3-arch.jpg create mode 100644 static/imgs/v3/manual/java/protocol/http3-qps.jpg create mode 100644 static/imgs/v3/manual/java/protocol/http3-rt.jpg create mode 100644 static/imgs/v3/manual/java/protocol/rest-arg.jpg 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 0000000000000000000000000000000000000000..629b2103eccc26b01ca01e116d8c5402eca5a592 GIT binary patch literal 136852 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 z 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 KX3gN`=KleHZW|u} literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0ad9aab8ef0369e95f53e2dfa71c6a28b53d6296 GIT binary patch literal 80611 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4bae0668224c186f82ca9a52168d80a32741e398 GIT binary patch literal 57283 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
9xRBdAxGnblrF_)L-Dg5JzOU^vVI>dQz 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 literal 0 HcmV?d00001