Apollo-link-ws Options Authorization 后端拿不到值

65 阅读1分钟
官网入口

环境: 

前端:ng9 后端: nestjs

问题:

在初始化建立graphql连接时,后端拿不到前端传的登录信息。 ps: 只在ng9出现,ng8正常。

解决方案:

找到 
直接看注释old method和new method

import { ActivatedRoute, Router } from '@angular/router';
import { HttpErrorResponse, HttpHeaders } from '@angular/common/http';

import { HttpLink } from 'apollo-angular-link-http';
import { onError } from 'apollo-link-error';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { setContext } from 'apollo-link-context';
import { ApolloLink } from 'apollo-link';
import { WebSocketLink } from 'apollo-link-ws';
import { getMainDefinition } from 'apollo-utilities';

import { OperationDefinitionNode } from 'graphql';
import { NgForage } from 'ngforage';


export interface CreateApolloParams {
    httpLink: HttpLink;
    ngForage: NgForage;
    domainId: number;
    router: Router;
    activatedRoute: ActivatedRoute;
    production: boolean;
    uri: string;
    wsUri: string;
}

export function createApollo(params: CreateApolloParams): any {

    const { httpLink, ngForage, notification, domainId, production, uri, wsUri, router, activatedRoute } = params;
    // Http link
    const http = httpLink.create({ uri });

    // Cached storage for the user token
    let token;

    // Authentication
    const withToken = setContext(async () => {
        // if you have a cached value, return it immediately
        // if (token) { return token; } no using cached

        token = await ngForage.getItem('TOKEN_DATA');
    });

    // Flow link
    const authFlowLink = withToken;

    // Middleware
    const authMiddleware = new ApolloLink((operation, forward) => {
        // add the authorization to the headers

        // if (production) {
        if (token) {
            operation.setContext({
                headers: new HttpHeaders().set('Authorization', `Bearer ${token}`)
            });
        }
        // }
        return forward(operation);
    });

    // Afterware
    const afterwareLink = new ApolloLink((operation, forward) => {
        return forward(operation).map(response => {
            return response;
        });
    });

    // Error link
    const errorLink = onError(({ graphQLErrors, networkError, response }) => {
        if (graphQLErrors) {
            graphQLErrors.map(({ message, locations, path }) =>
                console.error(
                    `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
                )
            );

            for (const err of graphQLErrors) {

              		// detail actions
                }
            }
        }

        if (networkError) {
            console.error(`[Network error]:`, networkError);
            if (networkError instanceof HttpErrorResponse) {
                const httpErrorResponse: HttpErrorResponse = new HttpErrorResponse(networkError);

                throw httpErrorResponse;
            }
        }
    });

    // Create a WebSocket link:
    const ws = new WebSocketLink({
        uri: wsUri,
        options: {
            reconnect: true,
            /* old method
            connectionParams: Authorization: `Bearer ${token}`
			*/
			// new method
            connectionParams: () => {
                return {
                    Authorization: `Bearer ${token}`,
                };
            }
        }
    });

    const splitLink = ApolloLink.split(
        // split based on operation type
        ({ query }) => {
            const { kind, operation } = getMainDefinition(query) as OperationDefinitionNode;
            return kind === 'OperationDefinition' && operation === 'subscription';
        },
        ws,
        http
    );
    return {
        link: ApolloLink.from([
            authFlowLink,
            authMiddleware,
            afterwareLink,
            errorLink,
            splitLink
            // http
        ]),
        cache: new InMemoryCache({
            // why? see
            // https://stackoverflow.com/questions/48840223/apollo-duplicates-first-result-to-every-node-in-array-of-edges/49249163#49249163
            dataIdFromObject: (o: any) => (o._id ? `${o.__typename}:${o._id}` : void (0))
        }),
        defaultOptions: {
            watchQuery: {
                fetchPolicy: 'network-only',
                errorPolicy: 'ignore',
            },
            query: {
                fetchPolicy: 'network-only',
                errorPolicy: 'all',
            },
            mutate: {
                errorPolicy: 'all'
            }
        }
    };
}


分析: 在新建WebSocketLink时,参数connectionParams可以是一个变量,也可以是一个方法的返回值,这里把变量改成函数就ok了。 当然,方法不唯一,并且目前国内用Graphql的人也比较少,相对来说挖坑的多于填坑的,这篇算是一个填坑记录吧。