添加自定义 header 到 apollo 客户端轮询请求

Add custom header to apollo client polling request

我正在使用 apollo-client 库从我的 Graphql 服务器查询数据。通过 apollo 轮询功能,每 5 秒向服务器发送一些查询。

是否有一种通用方法可以向我的轮询客户端发送的所有请求添加自定义 header?

两种解决方案

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

快速简便的解决方案

优势

  • 很快
  • 并且...简单

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

使用网络 Link 中间件的一般解决方案

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

来自文档:

Apollo Client has a pluggable network interface layer, which can let you configure how queries are sent over HTTP

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

优势:

  • 任何graphql操作都可以使用中间件的逻辑(你设置条件)
  • 您的查询不需要 "care" 或知道 HTTP headers
  • 您可以在决定是否将 header 添加到请求中以及添加什么之前进行更多处理。
  • 等等..

设置上下文

与快速简便的解决方案相同,只是这次我们不直接设置 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 link

之前某处的网络链
const client = new ApolloClient({
  // ...
  link: ApolloLink.from([
    pancakesLink,
    <yourHttpLink>
  ])
})

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

就这样了!你现在应该从服务器上拿些煎饼来。希望这会有所帮助。

Tal Z 的回答很好。但是,我想我只是粘贴如何实现他为那些使用 Angular.

的人列出的两种方法

为每个单独的 apollo 调用添加 header

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


  }

}

在中间件中添加header

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

按照 Diskdrive 的步骤,我将对 nextjs 的 getServerSideProps 做同样的事情

export async function getServerSideProps(context) {
  const cookies = context.req.headers.cookie;
  const token = getCookie("tokenId", cookies);

  const { data } = await client2.query({
    query: gql`
      query {
        me {
          firstName
          sureName
        }
      }
    `,
      context: {
        headers: {
          authorization: token,
        },
      },
  });

 
  return {
    props: {
      dataFromServer: data,
    },
  };
}