Apollo Server安卓客户端Header传递及x-api-key丢失问题求助
Apollo Gateway自定义Header丢失导致401错误排查
我在Apollo Server(Lambda环境)中使用自定义Header参数时遇到问题:通过端口3000的GraphQL Playground调用CONFIGURATIONSERVICE子图时,请求中缺少代码里添加的x-api-key Header,触发401授权错误。以下是我的代码:
import { ApolloServer } from 'apollo-server-lambda' import { ApolloGateway, IntrospectAndCompose, GraphQLDataSourceProcessOptions, RemoteGraphQLDataSource } from '@apollo/gateway' import { ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core' import { GraphQLRequest } from 'apollo-server-types' import { SignatureV4 } from '@aws-sdk/signature-v4' import { Sha256 } from '@aws-crypto/sha256-js' import { OutgoingHttpHeader } from 'http' import { defaultProvider } from '@aws-sdk/credential-provider-node' import { HttpRequest } from '@aws-sdk/protocol-http' class AuthenticatedDataSource extends RemoteGraphQLDataSource { /** * Adds the necessary IAM Authorization headers for AppSync requests * @param request The request to Authorize * @returns The headers to pass through to the request */ private async getAWSCustomHeaders(request: GraphQLRequest): Promise<{ [key: string]: OutgoingHttpHeader | undefined }> { const { http, ...requestWithoutHttp } = request if (!http) return {} const url = new URL(http.url) //check local env if(url.host.match(/localhost:20002/)) return {'x-api-key':'da2-fakeApiId123456'} // If the graph service is not AppSync, we should not sign these request. if (!url.host.match(/appsync-api/)) return {} const httpRequest = new HttpRequest({ hostname: url.hostname, path: url.pathname, method: http.method, headers: { Host: url.host, 'Content-Type': 'application/json' }, body: JSON.stringify(requestWithoutHttp), }) const signedRequest = await new SignatureV4({ region: 'eu-west-1', credentials: defaultProvider(), service: 'appsync', sha256: Sha256, }).sign(httpRequest) return signedRequest.headers || {} } /** * Customize the request to AppSync * @param options The options to send with the request */ public async willSendRequest({ request, context }: GraphQLDataSourceProcessOptions) { const customHeaders = await this.getAWSCustomHeaders(request) if (customHeaders) { Object.keys(customHeaders).forEach((h) => { request.http?.headers.set(h, customHeaders[h] as string) }) } // context not available when introspecting if (context.event) Object.keys(context.event.requestContext.authorizer.lambda).forEach((h) => { request.http?.headers.set(h, context.event.requestContext.authorizer.lambda[h] as string) }) } } const server = new ApolloServer({ gateway: new ApolloGateway({ buildService({ url }) { return new AuthenticatedDataSource({ url }) }, supergraphSdl: new IntrospectAndCompose({ subgraphs: [ { name: 'CONFIGURATIONSERVICE', url: process.env.CONFIGURATION_SERVICE_API_URL } ] }) }), debug: true, context: ({ event, context, express}) => ({ headers: event.headers, functionName: context.functionName, event, context, expressRequest: express.req, }), introspection: true, plugins: [ApolloServerPluginLandingPageGraphQLPlayground()], }) exports.handler = server.createHandler({ expressGetMiddlewareOptions: { cors: { origin: '*', } } })
排查方向及修复建议
验证URL匹配逻辑
确认process.env.CONFIGURATION_SERVICE_API_URL的实际值,检查url.host是否匹配localhost:20002。可以在getAWSCustomHeaders中添加日志打印当前URL的host:const url = new URL(http.url) console.log('当前子图URL Host:', url.host) // 打印用于验证如果日志显示host不是
localhost:20002,说明环境变量配置有误,或者URL格式问题(比如包含路径前缀)。检查
request.http是否存在
代码中使用可选链request.http?.headers.set,如果request.http为undefined,Header无法被设置。添加判断和日志:public async willSendRequest({ request, context }: GraphQLDataSourceProcessOptions) { const customHeaders = await this.getAWSCustomHeaders(request) if (!request.http) { console.warn('请求对象无http属性,无法设置Header') return } if (customHeaders) { Object.keys(customHeaders).forEach((h) => { request.http.headers.set(h, customHeaders[h] as string) }) } // 其余逻辑... }临时跳过分支验证
临时修改getAWSCustomHeaders,直接返回x-api-key,测试是否能正常携带:private async getAWSCustomHeaders(request: GraphQLRequest): Promise<{ [key: string]: OutgoingHttpHeader | undefined }> { // 临时注释原有逻辑,强制返回Header return {'x-api-key':'da2-fakeApiId123456'} // 原有逻辑... }如果此时请求成功,说明问题出在URL匹配的分支判断,需重新调整匹配规则(比如使用
url.hostname或包含端口的完整匹配)。确认Header大小写一致性
虽然HTTP Header不区分大小写,但部分服务可能强制要求小写的x-api-key。确保代码中设置的键名为小写,且子图服务能正确解析该Header。
内容的提问来源于stack exchange,提问作者Onur
相关产品推荐
相关产品推荐

