此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring GraphQL 1.4.1spring-doc.cadn.net.cn

服务器传输

Spring for GraphQL 支持通过 HTTP、WebSocket 和 RS索克特。spring-doc.cadn.net.cn

HTTP

GraphQlHttpHandler通过 HTTP 请求处理 GraphQL,并委托给拦截链以执行请求。有两种变体,一种用于 Spring MVC 和一个用于 Spring WebFlux。两者都异步处理请求,并且具有 等效功能,但分别依赖于阻塞与非阻塞 I/O 编写 HTTP 响应。spring-doc.cadn.net.cn

请求必须将 HTTP POST 与"application/json"作为内容类型和 GraphQL 请求详细信息 作为 JSON 包含在请求正文中。客户端可以请求"application/graphql-response+json"介质类型 以获取官方 GraphQL over HTTP 规范中定义的行为。 如果客户没有表达任何偏好,这将是选择的内容类型。 客户还可以申请遗产"application/json"media 类型来获取传统的 HTTP 行为。spring-doc.cadn.net.cn

实际上,如果服务器不可用,GraphQL HTTP 客户端应期望 4xx/5xx HTTP 响应,安全凭据 缺少或请求正文不是有效的 JSON。"application/graphql-response+json"响应还将使用 4xx 状态,如果客户端发送的 GraphQL 文档无法解析或被 GraphQL 引擎视为无效。 在这种情况下,"application/json"响应仍将使用 200 (OK)。 成功验证 GraphQL 请求后,HTTP 响应状态始终为 200 (OK), 并且 GraphQL 请求执行的任何错误都会出现在 GraphQL 响应的“错误”部分中。spring-doc.cadn.net.cn

GraphQlHttpHandler可以通过声明RouterFunctionbean 并使用RouterFunctions从 Spring MVC 或 WebFlux 创建路由。Boot Starter 执行此作,请参阅 Web 端点部分 详细信息,或检查GraphQlWebMvcAutoConfigurationGraphQlWebFluxAutoConfiguration它包含实际配置。spring-doc.cadn.net.cn

默认情况下,GraphQlHttpHandler将使用HttpMessageConverter(春季MVC) 和DecoderHttpMessageReader/EncoderHttpMessageWriter(WebFlux) 在 Web 框架中配置。 在某些情况下,应用程序将以与 GraphQL 有效负载不兼容的方式为 HTTP 端点配置 JSON 编解码器。 应用程序可以实例化GraphQlHttpHandler使用将用于 GraphQL 有效负载的自定义 JSON 编解码器。spring-doc.cadn.net.cn

此存储库的 1.0.x 分支包含一个 Spring MVC HTTP 示例应用程序。spring-doc.cadn.net.cn

服务器发送的事件

GraphQlSseHandler与上面列出的 HTTP 处理程序非常相似,但这次通过 HTTP 处理 GraphQL 请求 使用服务器发送事件协议。使用此传输,客户端必须使用"application/json"作为内容类型,GraphQL 请求详细信息以 JSON 形式包含在请求正文中;唯一的 与普通 HTTP 变体的区别在于客户端必须发送"text/event-stream"作为"Accept"请求 页眉。响应将作为一个或多个服务器发送事件发送。spring-doc.cadn.net.cn

这也在建议的 GraphQL over HTTP 规范中定义。 Spring for GraphQL 仅实现“不同连接模式”,因此应用程序必须考虑可扩展性问题 以及采用 HTTP/2 作为底层传输是否有帮助。spring-doc.cadn.net.cn

主要用例GraphQlSseHandlerWebSocket 传输的替代方法,接收项目流作为对 订阅作。此处不支持其他类型的作,例如查询和突变,并且应该 使用纯 JSON over HTTP 传输变体。spring-doc.cadn.net.cn

文件上传

作为一种协议,GraphQL 专注于文本数据的交换。这不包括二进制 图像等数据,但有一个单独的非正式 graphql-multipart-request-spec 允许通过 HTTP 使用 GraphQL 上传文件。spring-doc.cadn.net.cn

Spring for GraphQL 不支持graphql-multipart-request-spec径直。 虽然该规范确实提供了统一的 GraphQL API 的好处,但实际体验 导致了许多问题,并且最佳实践建议已经演变,请参阅 Apollo Server 文件上传最佳实践 以获得更详细的讨论。spring-doc.cadn.net.cn

如果您想使用graphql-multipart-request-spec在您的应用程序中,您可以 通过库 multipart-spring-graphql 执行此作。spring-doc.cadn.net.cn

Web套接字

GraphQlWebSocketHandler根据 graphql-ws 库中定义的协议处理 GraphQL over WebSocket 请求。使用的主要原因 基于 WebSocket 的 GraphQL 是允许发送 GraphQL 流的订阅 response,但它也可以用于具有单个响应的常规查询。 处理程序将每个请求委托给拦截链,以便进一步 请求执行。spring-doc.cadn.net.cn

基于 WebSocket 协议的 GraphQL

有两个这样的协议,一个在 subscriptions-transport-ws 库中,另一个在 graphql-ws 库中。前者不活跃,并且 由后者继任。阅读这篇博文了解历史。spring-doc.cadn.net.cn

有两种变体GraphQlWebSocketHandler,一个用于 Spring MVC,一个用于 Spring WebFlux 的 WebFlux。两者都异步处理请求并具有等效功能。 WebFlux 处理程序还使用非阻塞 I/O 和背压来流式传输消息, 这效果很好,因为在 GraphQL Java 中订阅响应是响应式流Publisher.spring-doc.cadn.net.cn

graphql-ws项目列出了许多供客户使用的配方spring-doc.cadn.net.cn

GraphQlWebSocketHandler可以通过声明SimpleUrlHandlerMappingbean 并使用它将处理程序映射到 URL 路径。默认情况下, Boot Starter 不会通过 WebSocket 端点公开 GraphQL, 但您可以为终结点路径添加属性来启用它。请查看启动参考文档中的 Web 端点,以及支持的列表spring.graphql.websocket 属性。 您还可以查看GraphQlWebMvcAutoConfigurationGraphQlWebFluxAutoConfiguration以获取实际的引导自动配置详细信息。spring-doc.cadn.net.cn

此存储库的 1.0.x 分支包含一个 WebFlux WebSocket 示例应用程序。spring-doc.cadn.net.cn

RS袜子

GraphQlRSocketHandler处理 GraphQL over RSocket 请求。查询和突变是 预期并作为 RSocket 处理request-response交互,而订阅是 处理为request-stream.spring-doc.cadn.net.cn

GraphQlRSocketHandler可以使用来自@Controller映射到 GraphQL 请求的路由。例如:spring-doc.cadn.net.cn

import java.util.Map;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.graphql.server.GraphQlRSocketHandler;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.stereotype.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);
	}
}

拦截

服务器传输允许在 GraphQL Java 引擎之前和之后拦截请求 调用来处理请求。spring-doc.cadn.net.cn

WebGraphQlInterceptor

HTTPWebSocket 传输调用 0 或更多链WebGraphQlInterceptor,后跟一个ExecutionGraphQlService调用 GraphQL Java 引擎。 拦截器允许应用程序拦截传入请求,以便:spring-doc.cadn.net.cn

例如,拦截器可以将 HTTP 请求标头传递给DataFetcher:spring-doc.cadn.net.cn

import java.util.Collections;

import reactor.core.publisher.Mono;

import org.springframework.graphql.data.method.annotation.ContextValue;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.server.WebGraphQlInterceptor;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.stereotype.Controller;

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通过控制器:spring-doc.cadn.net.cn

import graphql.GraphQLContext;
import reactor.core.publisher.Mono;

import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.server.WebGraphQlInterceptor;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Controller;

// 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:spring-doc.cadn.net.cn

import java.util.List;

import graphql.GraphQLError;
import graphql.GraphqlErrorBuilder;
import reactor.core.publisher.Mono;

import org.springframework.graphql.server.WebGraphQlInterceptor;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;

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链。这是受支持的 通过启动Starters,请参阅 Web 端点spring-doc.cadn.net.cn

WebSocketGraphQlInterceptor

WebSocketGraphQlInterceptor延伸WebGraphQlInterceptor带有额外的回调 除了客户端之外,还处理 WebSocket 连接的开始和结束 取消订阅。同样也会拦截 WebSocket 连接。spring-doc.cadn.net.cn

WebGraphQlHandler配置WebGraphQlInterceptor链。这是受支持的 通过启动Starters,请参阅 Web 端点。 最多可以有一个WebSocketGraphQlInterceptor在一连串拦截器中。spring-doc.cadn.net.cn

有两个内置的 WebSocket 拦截器,称为AuthenticationWebSocketInterceptor, 一个用于 WebMVC,一个用于 WebFlux 传输。这些有助于提取身份验证 详细信息"connection_init"GraphQL over WebSocket 消息、authenticate、 然后传播SecurityContext到 WebSocket 连接上的后续请求。spring-doc.cadn.net.cn

spring-graphql-examples 中有一个 websocket-authentication 示例。

RSocketQlInterceptor

WebGraphQlInterceptorRSocketQlInterceptor允许拦截 GraphQL Java 引擎执行前后基于 RSocket 请求的 GraphQL。您可以使用 this 来自定义graphql.ExecutionInputgraphql.ExecutionResult.spring-doc.cadn.net.cn