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

时间:2018-02-01 08:53:18

标签: javascript graphql apollo apollo-client graphql-js

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

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

2 个答案:

答案 0 :(得分:24)

两种解决方案

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

快速简便的解决方案

<强>优点

  • 很快
  • 和......简单

配置查询后,您可以使用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  
  }
})

使用网络链接中间件的常规解决方案

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

来自文档:

  

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

详细了解Apollo Link, the network link and Middleware concepts

<强>优点

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

设置背景

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

options: { 
  context: { 
    canHazPancakes: true //this will not reach the server
  }
}

添加中间件

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
    }
  }
})

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

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

文档中还有另一个有用的示例:using a middleware for authentication

就是这样!你现在应该从服务器上获得一些煎饼。希望这会有所帮助。

答案 1 :(得分:1)

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

为每个单独的阿波罗呼叫添加标题

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
      });


  }

}

在中间件中添加标题

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 {}