2. 服务器传输
Spring for GraphQL 支持通过 HTTP、WebSocket 和 RS索克特。
2.1. HTTP
GraphQlHttpHandler
通过 HTTP 请求处理 GraphQL,并委托给拦截链以执行请求。有两种变体,一种用于
Spring MVC 和一个用于 Spring WebFlux。两者都异步处理请求,并且具有
等效功能,但分别依赖于阻塞与非阻塞 I/O
编写 HTTP 响应。
请求必须将 HTTP POST 与"application/json"
作为内容类型和 GraphQL 请求详细信息
作为 JSON 包含在请求正文中,如建议的 GraphQL over HTTP 规范中所定义。
成功解码 JSON 正文后,HTTP 响应状态始终为 200 (OK),
并且 GraphQL 请求执行的任何错误都会出现在 GraphQL 响应的“错误”部分中。
媒体类型的默认和首选选项是"application/graphql-response+json"
但"application/json"
也受支持,如规范中所述。
GraphQlHttpHandler
可以通过声明RouterFunction
bean 并使用RouterFunctions
从 Spring MVC 或 WebFlux 创建路由。Boot Starter 执行此作,请参阅 Web 端点部分
详细信息,或检查GraphQlWebMvcAutoConfiguration
或GraphQlWebFluxAutoConfiguration
它包含实际配置。
此存储库的 1.0.x 分支包含一个 Spring MVC HTTP 示例应用程序。
2.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 执行此作。
2.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
可以通过声明SimpleUrlHandlerMapping
bean 并使用它将处理程序映射到 URL 路径。默认情况下,
Boot Starter 不会通过 WebSocket 端点公开 GraphQL,但它很容易
通过为终结点路径添加属性来启用它。有关详细信息,请参阅 Web 端点部分,或查看GraphQlWebMvcAutoConfiguration
或GraphQlWebFluxAutoConfiguration
用于实际的Starters配置。
此存储库的 1.0.x 分支包含一个 WebFlux WebSocket 示例应用程序。
2.3. RSocket
GraphQlRSocketHandler
通过 RSocket 处理 GraphQL 请求。查询和突变是预期的并作为 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);
}
}
2.4. 拦截
服务器传输允许在 GraphQL Java 引擎之前和之后拦截请求调用来处理请求。
2.4.1.WebGraphQlInterceptor
HTTP 和 WebSocket 传输调用0 或更多链WebGraphQlInterceptor
,后跟一个ExecutionGraphQlService
调用GraphQL Java 引擎。WebGraphQlInterceptor
允许应用程序拦截传入请求,并执行以下作之一:
-
检查 HTTP 请求详细信息
-
自定义
graphql.ExecutionInput
-
添加 HTTP 响应标头
-
自定义
graphql.ExecutionResult
例如,拦截器可以将 HTTP 请求标头传递给DataFetcher
:
class RequestHeaderInterceptor 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 MyContextValueController { (2)
@QueryMapping
Person person(@ContextValue String myHeader) {
...
}
}
1 | 拦截器将 HTTP 请求标头值添加到 GraphQLContext 中 |
2 | 数据控制者方法访问值 |
相反,拦截器可以访问添加到GraphQLContext
通过控制器:
// Subsequent access from a WebGraphQlInterceptor
class ResponseHeaderInterceptor 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());
});
}
}
@Controller
class MyCookieController {
@QueryMapping
Person person(GraphQLContext context) { (1)
context.put("cookieName", "123");
...
}
}
1 | 控制器为GraphQLContext |
2 | Interceptor 使用该值添加 HTTP 响应标头 |
WebGraphQlHandler
可以修改ExecutionResult
,例如,检查和修改请求验证错误,这些错误在执行开始之前引发,并且无法使用DataFetcherExceptionResolver
:
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();
})
.toList();
return response.transform(builder -> builder.errors(errors).build()); (3)
});
}
}
1 | 如果ExecutionResult 具有非空值的“data”键 |
2 | 检查和转换 GraphQL 错误 |
3 | 更新ExecutionResult 修改后的错误 |
用WebGraphQlHandler
配置WebGraphQlInterceptor
链。 这被 Boot Starter 支持,请参阅 Web 端点。
2.4.2.RSocketQlInterceptor
似WebGraphQlInterceptor
一RSocketQlInterceptor
允许在 GraphQL Java 引擎执行之前和之后拦截GraphQL over RSocket 请求。您可以使用this 来自定义graphql.ExecutionInput
和graphql.ExecutionResult
.