3. 服务器传输
Spring for GraphQL 支持通过 HTTP、WebSocket 和 RSocket 的
3.1. HTTP协议
GraphQlHttpHandler
处理 GraphQL over HTTP 请求,并委托给拦截链执行请求。有两种变体,一种用于
Spring MVC 和一个用于 Spring WebFlux 的 Spring WebFlux。两者都异步处理请求,并且具有
等效功能,但分别依赖于阻塞和非阻塞 I/O
编写 HTTP 响应。
请求必须使用 HTTP POST,并将 GraphQL 请求详细信息作为 JSON 包含在
请求正文,如提议的 GraphQL over HTTP 规范中所定义。成功解码 JSON 正文后,HTTP 响应
status 始终为 200 (OK),并且 GraphQL 请求执行中的任何错误都会显示在
“errors” 部分。媒体类型的默认和首选选择是 ,但也受支持,如
规范。"application/graphql+json"
"application/json"
GraphQlHttpHandler
可以通过声明 bean 并使用 from Spring MVC 或 WebFlux 创建路由来公开为 HTTP 端点。这
Boot starter 执行此操作,请参阅 Web 端点部分
details 或选中 or it contains,以获取实际配置。RouterFunction
RouterFunctions
GraphQlWebMvcAutoConfiguration
GraphQlWebFluxAutoConfiguration
Spring for GraphQL 存储库包含一个 Spring MVC HTTP 示例应用程序。
3.1.1. 文件上传
作为一种协议,GraphQL 专注于文本数据的交换。这不包括二进制文件 数据,但有一个单独的非正式 graphql-multipart-request-spec 允许通过 HTTP 使用 GraphQL 上传文件。
Spring for GraphQL 不支持直接。
虽然该规范确实提供了统一 GraphQL API 的好处,但实际体验确实
导致了许多问题,最佳实践建议已经发展起来,请参阅 Apollo Server 文件上传最佳实践 有关更详细的讨论。graphql-multipart-request-spec
如果您想在应用程序中使用,您可以
通过库 multipart-spring-graphql 执行此操作。graphql-multipart-request-spec
3.2. WebSocket 浏览器
GraphQlWebSocketHandler
根据 graphql-ws 库中定义的协议处理 WebSocket 上的 GraphQL 请求。使用的主要原因
基于 WebSocket 的 GraphQL 是允许发送 GraphQL 流的订阅
responses,但它也可以用于具有单个响应的常规查询。
处理程序将每个请求委托给 Interception 链以进一步
请求执行。
基于 WebSocket 协议的 GraphQL
有两种这样的协议,一种在 subscriptions-transport-ws 库中,另一种在 graphql-ws 库中。前者不活跃且 由后者接替。阅读这篇博文了解历史。 |
有两种变体,一种用于 Spring MVC,一种用于 Spring MVC
Spring WebFlux 的 Web Flux 中。两者都异步处理请求,并且具有等效的功能。
WebFlux 处理程序还使用非阻塞 I/O 和背压来流式传输消息,
这很好用,因为在 GraphQL Java 中,订阅响应是 Reactive Streams 。GraphQlWebSocketHandler
Publisher
该项目列出了许多供客户使用的配方。graphql-ws
GraphQlWebSocketHandler
可以通过声明 Bean 并使用它将处理程序映射到 URL 路径来公开为 WebSocket 端点。默认情况下,
Boot Starters不会通过 WebSocket 端点公开 GraphQL,但很容易
通过为 Endpoint path 添加属性来启用它。有关详细信息,请参阅 Web 端点部分,或查看 或 以获取实际的 Boot starter 配置。SimpleUrlHandlerMapping
GraphQlWebMvcAutoConfiguration
GraphQlWebFluxAutoConfiguration
Spring for GraphQL 存储库包含一个 WebFlux WebSocket 示例应用程序。
3.3. RSocket
GraphQlRSocketHandler
处理 GraphQL over RSocket 请求。查询和更改是
预期并作为 RSocket 交互处理,而订阅是
处理为 .request-response
request-stream
GraphQlRSocketHandler
可以使用映射到
GraphQL 请求的路由。例如:@Controller
@Controller
public class GraphQlRSocketController {
private final GraphQlRSocketHandler handler;
GraphQlRSocketController(GraphQlRSocketHandler handler) {
this.handler = handler;
}
@MessageMapping("graphql")
public Mono<Map<String, Object>> handle(Map<String, Object> payload) {
return this.handler.handle(payload);
}
@MessageMapping("graphql")
public Flux<Map<String, Object>> handleSubscription(Map<String, Object> payload) {
return this.handler.handleSubscription(payload);
}
}
3.4. 拦截
服务器传输允许在 GraphQL Java 引擎之前和之后拦截请求 调用以处理请求。
3.4.1.WebGraphQlInterceptor
HTTP 和 WebSocket 传输调用一个
0 或更多 ,后跟调用
GraphQL Java 引擎。 允许应用程序拦截
incoming requests 并执行以下操作之一:WebGraphQlInterceptor
ExecutionGraphQlService
WebGraphQlInterceptor
-
检查 HTTP 请求详细信息
-
自定义
graphql.ExecutionInput
-
添加 HTTP 响应标头
-
自定义
graphql.ExecutionResult
例如,拦截器可以将 HTTP 请求标头传递给 :DataFetcher
class HeaderInterceptor implements WebGraphQlInterceptor { (1)
@Override
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
String value = request.getHeaders().getFirst("myHeader");
request.configureExecutionInput((executionInput, builder) ->
builder.graphQLContext(Collections.singletonMap("myHeader", value)).build());
return chain.next(request);
}
}
@Controller
class MyController { (2)
@QueryMapping
Person person(@ContextValue String myHeader) {
// ...
}
}
1 | Interceptor 将 HTTP 请求标头值添加到 GraphQLContext 中 |
2 | 数据控制器方法访问值 |
相反,拦截器可以访问控制器添加到 the 的值:GraphQLContext
@Controller
class MyController {
@QueryMapping
Person person(GraphQLContext context) { (1)
context.put("cookieName", "123");
}
}
// Subsequent access from a WebGraphQlInterceptor
class HeaderInterceptor implements WebGraphQlInterceptor {
@Override
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) { (2)
return chain.next(request).doOnNext(response -> {
String value = response.getExecutionInput().getGraphQLContext().get("cookieName");
ResponseCookie cookie = ResponseCookie.from("cookieName", value).build();
response.getResponseHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString());
});
}
}
1 | Controller 为GraphQLContext |
2 | Interceptor 使用该值添加 HTTP 响应标头 |
WebGraphQlHandler
可以修改 ,例如,检查和修改
请求验证错误,这些错误在执行开始之前引发,并且不能
用 :ExecutionResult
DataFetcherExceptionResolver
static class RequestErrorInterceptor implements WebGraphQlInterceptor {
@Override
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
return chain.next(request).map(response -> {
if (response.isValid()) {
return response; (1)
}
List<GraphQLError> errors = response.getErrors().stream() (2)
.map(error -> {
GraphqlErrorBuilder<?> builder = GraphqlErrorBuilder.newError();
// ...
return builder.build();
})
.collect(Collectors.toList());
return response.transform(builder -> builder.errors(errors).build()); (3)
});
}
}
1 | 如果具有非 null 值的 “data” 键,则返回相同的ExecutionResult |
2 | 检查并转换 GraphQL 错误 |
3 | 使用修改后的错误更新ExecutionResult |
用于配置链。这是支持的
通过 Boot Starter,请参阅 Web 端点。WebGraphQlHandler
WebGraphQlInterceptor
3.4.2.RSocketQlInterceptor
与 WebGraphQlInterceptor
类似,它允许拦截
GraphQL over RSocket 请求在 GraphQL Java 引擎执行之前和之后。您可以使用
this 自定义 和 .RSocketQlInterceptor
graphql.ExecutionInput
graphql.ExecutionResult