将自定义标头添加到apollo客户端轮询请求

Ron*_*dur 14 javascript apollo graphql graphql-js apollo-client

我正在使用apollo-client库来查询来自我的Graphql服务器的数据.一些查询通过apollo轮询能力每隔5秒发送到服务器.

有一种通用的方法可以为从我的客户端轮询发送的所有请求添加自定义标头吗?

谢谢你的帮助 :)

Tal*_*l Z 32

两种解决方案

有两种方法可以做到这一点.一个是快速和简单的,将适用于具有一些限制的特定查询,另一个是更安全的一般解决方案,可以用于多个查询.

快速简便的解决方案

好处

  • 它很快
  • 而且...很容易

配置查询时,可以使用包含options字段的字段对其进行配置context.其值context将由网络链处理.它context本身不会发送到服务器,但如果您向其添加headers字段,它将在HTTP请求中使用.

示例:

const someQuery = graphql(gql`query { ... }`, {
  options: { 
    context: { 
      headers: { 
        "x-custom-header: "pancakes"  // this header will reach the server
      } 
    },
    // ... other options  
  }
})
Run Code Online (Sandbox Code Playgroud)

使用Network Link中间件的常规解决方案

使用Apollo,您可以添加一个Apollo Link作为中间件,并根据context查询操作设置的请求添加自定义标头.

来自文档:

Apollo Client具有可插拔的网络接口层,可以让您配置通过HTTP发送查询的方式

阅读更多关于Apollo Link,网络链接和中间件概念的信息.

优点:

  • 中间件的逻辑可以被任何graphql操作使用(你设置条件)
  • 您的查询不需要"关心"或了解HTTP标头
  • 在决定是否以及要添加到请求的标头之前,您可以执行更多处理.
  • 和更多..

设置上下文

与快速简便的解决方案相同,只是这次我们没有headers直接设置:

options: { 
  context: { 
    canHazPancakes: true //this will not reach the server
  }
}
Run Code Online (Sandbox Code Playgroud)

添加中间件

Apollo有一个特定的中间件用于设置上下文apollo-link-context(使用更通用的中间件可以实现相同).

import {setContext} from 'apollo-link-context'

//... 

const pancakesLink = setContext((operation, previousContext) => { 
  const { headers, canHazPancakes } = previousContext
  if (!canHazPancakes) { 
    return previousContext
  }

  return {
    ...previousContext,
    headers: {    
      ...headers,
      "x-with-pancakes": "yes" //your custom header
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

不要忘记在http链接之前将其连接到网络链接

const client = new ApolloClient({
  // ...
  link: ApolloLink.from([
    pancakesLink,
    <yourHttpLink>
  ])
})
Run Code Online (Sandbox Code Playgroud)

文档中还有另一个有用的示例:使用中间件进行身份验证.

而已!你现在应该从服务器上得到一些煎饼.希望这可以帮助.

  • 好的,但是如果应用程序已经初始化并且 ApolloClient 已经创建,如何设置上下文? (4认同)
  • 这也是我的问题。中间件似乎无法动态标头......希望我错了?另外,我将如何在 &lt;Query&gt; 组件中实现这一点? (3认同)

Dis*_*ive 7

Tal Z 的回答非常好。但是,我想我只是粘贴如何实现他为使用 Angular 的人列出的两种方法。

为每个单独的 apollo 调用添加标头

import { Component, OnInit } from '@angular/core';
import { LocalStorageService } from 'angular-2-local-storage';
import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';
import { Pineapples, Pineapple } from './models/pineapples';

export class AppComponent {

  constructor(private apollo: Apollo,
    private localStorageService: LocalStorageService) {
  }

  callGraphQLQuery() {

    const token = this.localStorageService.get('loginToken');
    this.apollo
      .watchQuery<Pineapples>({

        query: gql`
        {
          pineapples{
            id
            name
          }
        }
      `, 
       context: {
           headers: new HttpHeaders().set("Authorization", "Bearer " + token),
         }
      })
      .valueChanges.subscribe(result => {
        // handle results here
      });


  }

}
Run Code Online (Sandbox Code Playgroud)

在中间件中添加标头

const uri = 'https://localhost:5001/graphql'; 

export function createApollo(httpLink: HttpLink, localStorage: LocalStorageService) {

  const http = httpLink.create({ uri });

  const authLink = new ApolloLink((operation, forward) => {
    // Get the authentication token from local storage if it exists
    const token = localStorage.get('loginToken');

    // Use the setContext method to set the HTTP headers.
    operation.setContext({
      headers: {
        'Authorization': token ? `Bearer ${token}` : ''
      }
    });

    // Call the next link in the middleware chain.
    return forward(operation);
  });

  return {
    link: authLink.concat(http),
    cache: new InMemoryCache()
  };
}

@NgModule({
  exports: [ApolloModule, HttpLinkModule],
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [HttpLink, LocalStorageService],
    },
  ],
})
export class GraphQLModule {}
Run Code Online (Sandbox Code Playgroud)