Netflix Java GraphQL Client:如何为CustomGraphQLClient动态添加请求头
动态添加请求头到CustomGraphQLClient的实现方案
问题背景
之前使用DefaultGraphQLClient时,我们可以在请求到来时动态添加请求头——因为部分特定请求头只有在客户端发送请求时才能确定。现在迁移到CustomGraphQLClient后,发现RequestExecutor只能在创建CustomGraphQLClient时传入,所有请求头必须预先定义,无法实现旧版的动态添加逻辑。
旧版实现代码:
@Bean(name = [CORE_PRODUCT_GRAPHQL_CLIENT]) fun coreGraphQLClient(): GraphQLClient { return DefaultGraphQLClient(url) } fun executeQuery(query: String, graphQLHeaders: GraphqlHeaderMaps? = null): GraphQLResponse { return graphQLClient.executeQuery(query, HashMap<String, List<String>>()) { url, headers, body -> val requestHeaders = HttpHeaders() headers.forEach(requestHeaders::put) graphQLHeaders?.forEach(requestHeaders::put) val exchange: ResponseEntity<String> = restTemplate.exchange( url, HttpMethod.POST, HttpEntity<Any?>(body, requestHeaders), String::class.java ) HttpResponse(exchange.statusCodeValue, exchange.body) } }
解决方案
方法1:自定义支持动态头的RequestExecutor
通过封装RequestExecutor,让它能在执行阶段接收额外请求头,同时保证线程安全:
class DynamicRequestExecutor(private val delegate: RequestExecutor) : RequestExecutor { // 用ThreadLocal存储当前请求的额外头,避免多线程冲突 private val extraHeaders = ThreadLocal<Map<String, List<String>>>() fun setExtraHeaders(headers: Map<String, List<String>>?) { extraHeaders.set(headers) } override fun execute(request: GraphQLRequest): GraphQLResponse { // 合并原有请求头与额外头 val mergedHeaders = request.headers.toMutableMap() extraHeaders.get()?.let { mergedHeaders.putAll(it) } val newRequest = request.copy(headers = mergedHeaders) // 执行后清理ThreadLocal,防止内存泄漏 try { return delegate.execute(newRequest) } finally { extraHeaders.remove() } } }
创建CustomGraphQLClient时注入这个动态执行器:
@Bean(name = [CORE_PRODUCT_GRAPHQL_CLIENT]) fun coreGraphQLClient(): GraphQLClient { val defaultExecutor = DefaultRequestExecutor(restTemplate) val dynamicExecutor = DynamicRequestExecutor(defaultExecutor) return CustomGraphQLClient(url, dynamicExecutor) }
执行查询时传入动态头:
fun executeQuery(query: String, graphQLHeaders: GraphqlHeaderMaps? = null): GraphQLResponse { val client = coreGraphQLClient() as CustomGraphQLClient val executor = client.requestExecutor as DynamicRequestExecutor executor.setExtraHeaders(graphQLHeaders) return client.executeQuery(query) }
方法2:直接通过executeQuery的headers参数传入
如果不需要在RequestExecutor中做统一处理,可直接在调用executeQuery时合并默认头与动态头:
fun executeQuery(query: String, graphQLHeaders: GraphqlHeaderMaps? = null): GraphQLResponse { val requestHeaders = HashMap<String, List<String>>() // 先添加预先定义的默认头 // requestHeaders.put("default-header", listOf("value")) // 再合并动态传入的请求头 graphQLHeaders?.let { requestHeaders.putAll(it) } return coreGraphQLClient().executeQuery(query, requestHeaders) }
注意事项
- 使用ThreadLocal方案时,必须在请求执行完成后清理ThreadLocal,避免线程复用导致的内存泄漏。
- 多线程环境下,ThreadLocal是线程安全的,但如果使用线程池,要确保线程复用前已清理ThreadLocal中的值。
内容的提问来源于stack exchange,提问作者Panda World
相关产品推荐
相关产品推荐

