3. 服务器传输
Spring for GraphQL 支持通过 HTTP、WebSocket 和 RS索克特。
3.1. HTTP
GraphQlHttpHandler通过 HTTP 请求处理 GraphQL,并委托给拦截链以执行请求。有两种变体,一种用于
Spring MVC 和一个用于 Spring WebFlux。两者都异步处理请求,并且具有
等效功能,但分别依赖于阻塞与非阻塞 I/O
编写 HTTP 响应。
请求必须使用 HTTP POST,并将 GraphQL 请求详细信息作为 JSON 包含在
请求正文,如建议的 GraphQL over HTTP 规范中所定义。成功解码 JSON 正文后,HTTP 响应
状态始终为 200 (OK),并且 GraphQL 请求执行的任何错误都会显示在
“errors”部分。媒体类型的默认和首选选项是"application/graphql+json"但"application/json"也受支持,如
规范。
GraphQlHttpHandler可以通过声明RouterFunctionbean 并使用RouterFunctions从 Spring MVC 或 WebFlux 创建路由。这
启动Starters执行此作,请参阅 Web 端点部分
详细信息,或检查GraphQlWebMvcAutoConfiguration或GraphQlWebFluxAutoConfiguration它包含实际配置。
Spring for GraphQL 存储库包含一个 Spring MVC HTTP 示例应用程序。
3.1.1. 文件上传
作为一种协议,GraphQL 专注于文本数据的交换。这不包括二进制 图像等数据,但有一个单独的非正式 graphql-multipart-request-spec 允许通过 HTTP 使用 GraphQL 上传文件。
Spring for GraphQL 不支持graphql-multipart-request-spec径直。
虽然该规范确实提供了统一 GraphQL API 的好处,但实际体验具有
导致了许多问题,并且最佳实践建议已经演变,请参阅 Apollo Server 文件上传最佳实践 以获得更详细的讨论。
如果您想使用graphql-multipart-request-spec在您的应用程序中,您可以
通过库 multipart-spring-graphql 执行此作。
3.2. Web套接字
GraphQlWebSocketHandler根据 graphql-ws 库中定义的协议处理 GraphQL over WebSocket 请求。使用的主要原因
基于 WebSocket 的 GraphQL 是允许发送 GraphQL 流的订阅
response,但它也可以用于具有单个响应的常规查询。
处理程序将每个请求委托给拦截链,以便进一步
请求执行。
|
基于 WebSocket 协议的 GraphQL
有两个这样的协议,一个在 subscriptions-transport-ws 库中,另一个在 graphql-ws 库中。前者不活跃,并且 由后者继任。阅读这篇博文了解历史。 |
有两种变体GraphQlWebSocketHandler,一个用于 Spring MVC,一个用于
Spring WebFlux 的 WebFlux。两者都异步处理请求并具有等效功能。
WebFlux 处理程序还使用非阻塞 I/O 和背压来流式传输消息,
这效果很好,因为在 GraphQL Java 中订阅响应是响应式流Publisher.
这graphql-ws项目列出了许多供客户使用的配方。
GraphQlWebSocketHandler可以通过声明SimpleUrlHandlerMappingbean 并使用它将处理程序映射到 URL 路径。默认情况下,
Boot Starters不会通过 WebSocket 端点公开 GraphQL,但它很容易
通过为终结点路径添加属性来启用它。有关详细信息,请参阅 Web 端点部分,或查看GraphQlWebMvcAutoConfiguration或GraphQlWebFluxAutoConfiguration用于实际的Starters配置。
Spring for GraphQL 存储库包含一个 WebFlux WebSocket 示例应用程序。
3.3. RSocket
GraphQlRSocketHandler处理 GraphQL over RSocket 请求。查询和突变是
预期并作为 RSocket 处理request-response交互,而订阅是
处理为request-stream.
GraphQlRSocketHandler可以使用来自@Controller映射到
GraphQL 请求的路由。例如:
@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 或更多WebGraphQlInterceptor,后跟一个ExecutionGraphQlService这调用
GraphQL Java 引擎。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 | 拦截器将 HTTP 请求标头值添加到 GraphQLContext 中 |
| 2 | 数据控制者方法访问值 |
相反,拦截器可以访问添加到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 | 控制器为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 | 如果ExecutionResult具有非空值的“data”键 |
| 2 | 检查和转换 GraphQL 错误 |
| 3 | 更新ExecutionResult修改后的错误 |
用WebGraphQlHandler配置WebGraphQlInterceptor链。这是受支持的
通过启动Starters,请参阅 Web 端点。
3.4.2.RSocketQlInterceptor
似WebGraphQlInterceptor一RSocketQlInterceptor允许拦截
GraphQL Java 引擎执行前后基于 RSocket 请求的 GraphQL。您可以使用
this 来自定义graphql.ExecutionInput和graphql.ExecutionResult.