我有一个Spring GraphQL项目,每个数据提取器(@schemaMap
)将从受身份验证保护的远程API获取数据。
我需要将授权头从原始请求(我可以在@QueryMapping
方法中看到)传播到数据获取程序。
在数据获取程序中,我可以使用RequestContextHolder获取请求和标题,如下所示:
val request = (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes?)?.getRequest()
val token = request?.getHeader("authorization")
这工作,但我担心它可能会打破。Spring GraphQL留档指出:
GraphQLJava调用的DataFetcher和其他组件可能并不总是与Spring MVC处理程序在同一线程上执行,例如,如果异步WebInterceptor或DataFetcher切换到不同的线程。
我试图添加一个ThreadLocalAccessor
组件,但在调试和阅读源代码的过程中,我发现restoreValue
方法只能在WebFlux项目中调用。
我如何确保在WebMvc项目中获得正确的RecestContextHolder
?
使现代化
我将添加一些代码来更好地解释我的用例。
CurrentActivity
是父实体,Booking
是子实体。
我需要从后端获取实体,API受身份验证保护。我在原始请求(带有graphql查询的请求)中收到了auth令牌。
CurrentActivityController。kt
@Controller
class CurrentActivityController @Autowired constructor(
val retrofitApiService: RetrofitApiService,
val request: HttpServletRequest
) {
@QueryMapping
fun currentActivity(graphQLContext: GraphQLContext): CurrentActivity {
// Get auth token from request.
// Can I use the injected request here?
// Or do I need to use Filter + ThreadLocalAccessor to get the token?
val token = request.getHeader("authorization")
// Can I save the token to GraphQL Context?
graphQLContext.put("AUTH_TOKEN", token)
return runBlocking {
// Authenticated API call to backend to get the CurrentActivity
return@runBlocking entityretrofitApiService.apiHandler.activitiesCurrent(mapOf("authorization" to token))
}
}
}
预订管理员。kt
@Controller
class BookingController @Autowired constructor(val retrofitApiService: RetrofitApiService) {
@SchemaMapping
fun booking(
currentActivity: CurrentActivity,
graphQLContext: GraphQLContext,
): Booking? {
// Can I retrieve the token from GraphQL context?
val token: String = graphQLContext.get("AUTH_TOKEN")
return runBlocking {
// Authenticated API call to backend to get Booking entity
return@runBlocking currentActivity.currentCarBookingId?.let { currentCarBookingId ->
retrofitApiService.apiHandler.booking(
headerMap = mapOf("authorization" to token),
bookingId = currentCarBookingId
)
}
}
}
}
ThreadLocalAccess
概念实际上是一种在环境中存储/恢复上下文值的方法,在该环境中,如果没有其他架构体系已经支持,则可以在不同的线程上异步执行。
在SpringWebFlux中,已经存在了反应器上下文并填充了这个角色。WebFlux应用程序应该使用反应DataFetcher
和反应器上下文。
ThreadLocalAccessor
实现对Spring MVC应用程序最有用。任何ThreadLocalAccessor
bean都将由启动程序自动配置。
在您的情况下,您可以遵循其中一个示例并进行类似的安排:
DataFetcher
我尝试添加ThreadLocalAccessor组件,但在调试和阅读源代码的过程中,我发现restoreValue方法只在WebFlux项目中被调用。
请注意,只有当当前Thread不是最初提取的值时,才调用restoreValue
(不需要做任何事情,值已经在Threadlocal
中)。
我已经成功地测试了这种方法,从RequestContextHolder
获取“authorization”HTTP头值。您似乎尝试过这种方法,但没有成功——您能否尝试使用1.0.0-M3,如果不起作用,请告知我们?您可以在项目上创建一个问题,并链接到复制该问题的示例项目。
如果不想处理ThreadLocal
绑定的值,可以始终使用WebInterceptor
使用自定义值扩充GraphQLContext
。
下面是一个例子:
java prettyprint-override">@Component
public class AuthorizationWebInterceptor implements WebInterceptor {
@Override
public Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain chain) {
String authorization = webInput.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
webInput.configureExecutionInput((input, inputBuilder) ->
inputBuilder
.graphQLContext(contextBuilder -> contextBuilder.put("Authorization", authorization))
.build()
);
return chain.next(webInput);
}
}
这样,您就可以从GraphQL上下文中获取该值:
@QueryMapping
public String greeting(GraphQLContext context) {
String authorization = context.getOrDefault("Authorization", "default");
return "Hello, " + authorization;
}
获取当前请求的所有HTTP 请求头信息,如: $headers = $request->header(); print_r($headers); 直接获取某个请求头信息,如: $token = $request->header('XX-Token'); HTTP请求头信息的名称不区分大小写,并且下划线会自动转换为-,所以下面的写法都是等效的: $token = $request->head
获取当前请求的所有HTTP 请求头信息,如: $headers = $request->header(); print_r($headers); 直接获取某个请求头信息,如: $token = $request->header('XX-Token'); HTTP请求头信息的名称不区分大小写,并且下划线会自动转换为-,所以下面的写法都是等效的: $token = $request->head
这是我的AngularJS代码(如果我删除header选项,它可以正常工作)。 请求如下: 答复: 我添加了和头,但请求仍然失败 大写字母(我的意思是vs)是否会导致失败?如果是,我如何才能让AngularJS停止这样做? Go服务器路由代码:
问题内容: 我正在尝试教自己一些基本的网络抓取。使用Python的请求模块,在尝试以下操作之前,我能够抓取各种网站的html: 我得到的不是基本的html,而是本页面的内容: 我已经尝试过将get / post与我可以从文档,SO和其他示例中猜到的每种语法进行多种组合。我不明白上面看到的内容,无法将其转换为可以阅读的任何内容,也无法弄清楚如何获得自己真正想要的东西。我的问题是,如何获取以上页面的h
服务工作者内部的fetch事件似乎没有接收到请求头,尽管MDN文档中有说明: 通过调用FetchEvent返回的request对象的参数,可以检索关于每个请求的大量信息: 事件要求url 事件。要求方法 事件。要求标题 事件。要求身体 从主线程获取资源的代码: 在SW文件中获取事件处理程序: 记录每个fetch事件的标题会给我一个空对象: 标题{} 这阻止了我缓存这个只需要这两个头的特定请求。不需