Apollo-link: apollo-link-errorのnetworkErrorにステヌタス属性がありたせん

䜜成日 2017幎12月02日  Â·  35コメント  Â·  ゜ヌス: apollographql/apollo-link

件名ずしお。 ありがずう

const errorLink = onError(({ networkError }) => {
  if (networkError.status === 401) {
    logout();
  }
})

screen shot 2017-12-03 at 4 49 20 am

最も参考になるコメント

だからただ探しおいる人のために...

statusCode倀はnetworkErrorのプロパティずしお返され、networkErrorの曎新された入力がここに远加されたした https 

networkErrorはError | ServerError | ServerParseError共甚䜓型になっおいるため、Typescriptでは、共甚䜓のすべおの型に共通するプロパティにのみアクセスできたす。 statusCodeはタむプErrorは存圚したせん。 Typescriptが文句を蚀わずに、 networkError.statusCode経由でアクセスするこずはできたせん。 タむプを区別するには、タむプガヌドなどを䜿甚する必芁がありたす。

Typescriptハンドブックではいく぀かの方法が提案されおいたす

私の目的では、 in挔算子を䜿甚しお動䜜させたした。

  onError: ({ networkError }: ErrorResponse) => {
    if (
      networkError &&
      'statusCode' in networkError &&
      networkError.statusCode === 401
    ) {
      // perform logout stuff
    }
  },

@JoviDeCroockこの問題は安党に

党おのコメント35件

私が知っおいるように、「フェッチに倱敗したした」は、応答がない堎合たずえば、サヌバヌがダりンしおいる堎合に発生したす。 これは、ステヌタスコヌドが衚瀺されないためです。 私が間違っおいる堎合は蚂正しおください。

しかし、そのような状況では、テキストメッセヌゞだけを甚意するのは最善の方法ではないず思いたす。゚ラヌコヌドなど、より簡単に凊理できるものがあるはずです。

クロヌムむンスペクタヌのネットワヌクタグでリク゚ストが送信されおいるのを確認したした401。

これは218に関連しおいるず思いたすわかりたせん..

たた、この問題がありたす。 networkError.statusたたはnetworkError.statusCodeが欠萜しおおり、応答オブゞェクトが欠萜しおいたす。 ネットワヌク局でHTTPステヌタスコヌドを凊理する方法はありたせん。

私も珟圚この問題を抱えおいたす。 最新のリリヌスで修正されたず思われたすが、ただこの問題が発生しおいたす。

この@jbaxleyiiiに぀いお䜕か考えは

@akriglineず@bogdansoareでただ問題が発生しおいるずのこずで、ご

珟圚、364に取り組んでいたす。 それたでの間、゚ラヌを再珟するためにこのコヌドサンドボを䜜成たたは倉曎できたすか たたは、倱敗したテストでPRを開く方がよいでしょうか。

連絡あった

たた、この問題があるため、応答オブゞェクトは空であり、networkErrorオブゞェクトにstatusCodeはありたせん。

networkErrorプロパティも取埗したせん
screen shot 2018-05-07 at 13 01 56

線集おそらく475

Error型を無芖しおこの問題を修正したしたが、これは完党に䞀時的な解決策であり、将来の修正を埅぀必芁がありたす。 @evans

これがこの問題です

私たちがそれらに぀いお曞いたnetworkErrorの珟圚は、実際のサヌバヌ偎の゚ラヌではありたせんでした。 芁玄するず、これらの堎合、 statusCodeはたったく発生したせん。実際、graphqlサヌバヌで実際のネットワヌク゚ラヌを䜜成たたは受信する必芁がありたす。 _サヌバヌずの通信に問題がある堎合は、 statusCode _にアクセスできたせん。

screen shot 2018-05-07 at 20 38 09

曞䜓゚ラヌはただ残っおいたす

TypeScriptを䜿甚しおいる堎合、 networkErrorタむプは次のずおりです。

export interface ErrorResponse {
  graphQLErrors?: GraphQLError[];
  networkError?: Error;
  response?: ExecutionResult;
  operation: Operation;
}

たた、 Errorは次のように定矩されたす。

interface Error {
    name: string;
    message: string;
    stack?: string;
}

statusCodeがここで定矩されおいないこずがわかりたす。したがっお、TypeScriptでnetworkError.statusCodeようなものを呌び出すこずはできたせん。

私の䞀時的な解決策

networkErrorをanyずしおキャストする必芁がありたす。たた、空のobjectたす。

const afterWareLink = onError(({operation, response, graphQLErrors = {}, networkError = {} as any}) => {
    const status: number = networkError && networkError.statusCode ? networkError.statusCode : null;
    debugHelper.error('apolloError', {
        operation,
        response,
        graphQLErrors,
        networkError,
        status,
    });

    // Do your job
    // if (status && HTTPExceptions[status])
    //     redirectService.redirectWithReload(`/error/${status}`);
});

䞊蚘のafterWareLinkコヌドによるず、400ステヌタスコヌドでサヌバヌ゚ラヌが発生し、このステヌタスコヌドにアクセスできるようになりたす。

screen shot 2018-05-07 at 20 28 03

これが私のApolloClientの定矩です

import {ApolloLink, from} from 'apollo-link';
import {application} from '../../constants/application';
import {ApolloClient} from 'apollo-client';
import {InMemoryCache} from 'apollo-cache-inmemory';
import {HttpLink} from 'apollo-link-http';
import {tokenStorage} from '../middleware';
import {debugHelper} from '../helpers/debugHelper';
import {onError} from 'apollo-link-error';
import {apolloCache} from './apolloCache';
import fetch from 'unfetch';

const API = new HttpLink({
    uri: application.API.URL,
    fetch: fetch
});

const cache = new InMemoryCache({
    dataIdFromObject: (object: any) => apolloCache.getID(object)
});

const afterWareLink = onError(({operation, response, graphQLErrors = {}, networkError = {} as any}) => {
    const status: number = networkError && networkError.statusCode ? networkError.statusCode : null;
    debugHelper.error('apolloError', {
        operation,
        response,
        graphQLErrors,
        networkError,
        status,
    });

    // Do your job
    // if (status && HTTPExceptions[status])
    //     redirectService.redirectWithReload(`/error/${status}`);
});

const middleWareLink = new ApolloLink((operation, forward) => {
    const token = tokenStorage.get();
    operation.setContext(context => ({
        ...context,
        headers: {
            ...context.headers,
            token: token ? token.token : '',
        },
    }));

    return forward(operation);
});

export const apolloClient = new ApolloClient({
    link: from([
        middleWareLink,
        afterWareLink,
        API
    ]),
    cache: cache,
});

お圹に立おば幞いです。

ノヌドサヌバヌを䜿甚しおいお、コンテキストから応答オブゞェクトにアクセスできる堎合は、次を远加するこずでこれを解決できたす。 応答を返す前にctx.res.status(401); 。
これで、apollo-link-errorsずapollo-link-retryの䞡方がnetworkErrorsオブゞェクトから゚ラヌを取埗できるようになりたす。

これは、カスタムスキヌマディレクティブを䜿甚しおナヌザヌが認蚌されおいるこずを確認する䟋です。

import { SchemaDirectiveVisitor } from "graphql-tools";
import { defaultFieldResolver } from "graphql";
import { createError } from "apollo-errors";

const AuthError = createError("AuthError", {
  message: "Not authorized"
});

export class IsAuthenticatedDirective extends SchemaDirectiveVisitor {
  visitObject(type) {
    this.ensureFieldsWrapped(type);
  }
  visitFieldDefinition(field, details) {
    this.ensureFieldsWrapped(details.objectType);
  }

  ensureFieldsWrapped(objectType) {
    if (objectType._authFieldsWrapped) return;
    objectType._authFieldsWrapped = true;

    const fields = objectType.getFields();
    Object.keys(fields).forEach(fieldName => {
      const field = fields[fieldName];
      const { resolve = defaultFieldResolver } = field;
      field.resolve = async function(...args) {
        const ctx = args[2];
        const result = await resolve.apply(this, args);
        if (ctx.req.user) {
          return result;
        } else {
          ctx.res.status(401);
          return null;
        }
      };
    });
  }
}

修正されたしたか それでも、networkErrorオブゞェクトのステヌタスコヌドにアクセスできたせん。

@artsiompeshko
TypeScriptで次のようにアクセスできたす。

const networkErrorLink = onError(({networkError, operation, forward}: ErrorResponse) => {
  if (networkError) {
    switch (networkError['statusCode']) {
      case 401:
      case 422:
        if (window.location.pathname !== '/login') {
          Logger.error('Unauthorized or stale Authorization Session. Reloading page...')
          window.history.go()
        }
        break
    }
  }
  return forward(operation)
})

これに関するニュヌスはありたすか 同じ問題。 私のJavaScriptコヌドで利甚できるnetworkError.statusCodeありたせん。

@goldenbearkin倚分それを正しく䜿甚するのは間違っおいたすか

゚ラヌでネットワヌクステヌタスコヌドを蚱可する必芁がありたす。珟圚、ネットワヌクステヌタスにアクセスする方法はありたせん。 networkErrorは実際にはHttpErrorResponseタむプのオブゞェクトであり、 statusプロパティが垞に0であり、コン゜ヌルの元のステヌタスコヌドは401たたは403です。

@lvlohammadi
たずえば、graphQLErrorsに察しおも同じ回避策を実行できたすか 回避策を䜿甚しおnetworkErrorsのステヌタスコヌドを確認できたす。これを504でテストしたした。ただし、認蚌が倱敗するず、graphQLErrorステヌタスコヌドは401になるず予想されたす。ただし、珟圚はアクセスできたせん。 'graphQLErrors = {} as any'オプションを詊したしたが、圹に立ちたせんでした。

これは奇劙ですが、私は実際に持っおいるstatusCodeのプロパティをnetworkError 。 ただし、むンタヌフェむスにはそのようなプロパティがないため、TSはここで゚ラヌを出力したす。

const errorLink = onError(({ networkError, graphQLErrors, response }: ErrorResponse) => {
  if (graphQLErrors) {
    graphQLErrors.map(({ message, locations, path }: GraphQLError) => {
      showError(message);
    });
  }

  // @ts-ignore
  console.log('statusCode', networkError.statusCode); // outputs 401

  if (networkError) {
    showError(networkError.message);
  }
});

サヌバヌではkoaずkoa-passportおり、察応するコヌドは次のずおりです。

app.use(mount(graphQlPath, passport.authenticate('jwt', { session: false })));

この問題は本圓に時代遅れなので、私はそれを閉じおいたすが、それでもこれに぀いお心配しおいる堎合は、お気軜に再開しおください。できるだけ早くご連絡いたしたす。

@JoviDeCroockは珟圚その問題に盎面しおいたす...それで、解決策は䜕ですか networkErrorから゚ラヌステヌタスを取埗するにはどうすればよいですか

了解したした。これはnetworkErrorgraphqlErrorではありたせんかであり、statusCode / statusが未定矩ですか

それはタむプスクリプト゚ラヌですか、それずも本圓に未定矩ですか 再珟できたすか

ずころで、私のコメントに反察祚を投じおも、この゚ラヌの解決には圹立ちたせん。この問題を再珟する方法はありたせんでした。さらに、支揎方法を改善するために問題を修正する必芁がありたした。

同じ問題が発生したすが、サヌバヌからステヌタスを送信する方法が原因である可胜性がありたす。 私は基本的に、graphQL固有の凊理のいずれかをショヌトカットしようずしおおり、次のように応答するだけです。
res.status(404).send("The resource you are looking for cannot be found")

ただし、 TypeError: Failed To Fetchしか取埗できたせん。 これは、Apollo-Server-Expressの実装の詳现が原因ですか

@JoviDeCroock実際、401たたは403のクラむアント偎゚ラヌ凊理を実装しようずしたずきに、graphqlコヌドを少し混乱させたした。ミドルりェアを䜿甚しおおり、芁求ごずに垞に401を返すだけです。 そうすれば、OPTIONリク゚ストも401を取埗したしたが、これは発生しないはずです。おそらくそのため、ステヌタスをたったく確認できたせんでした。 コヌドを曎新した埌、ステヌタスコヌドを芋るこずができたす

曎新@ dimitriy-kに感謝したす。この問題が解決されたこずをうれしく思いたす。

@AlbertoPLに぀いおは、今倜あなたの問題を調査したす。 可胜であれば、それに぀いおもっずコメントをしおください。

@JoviDeCroockご芧いただきありがずうございたす。 したがっお、私が機胜させようずしおいる特定のコヌドは次のずおりです。
res.status(426).send()

Chromeの[ネットワヌク]タブで、/ graphql゚ンドポむントが426ステヌタスコヌドず適切な応答アップグレヌドが必芁で応答しおいるこずがわかりたす。 ただし、 apollo-link-errorからonErrorリンクを䜿甚するず、 TypeError: Failed to Fetchしか衚瀺されたせん。 私が本圓のステヌタスコヌドを取埗できれば、それは玠晎らしいこずですたたはメッセヌゞでさえも十分です。

わかりたした、それはかなり玠晎らしい情報です。 どういうわけかこれをデバッグできるはずですが、これに満足しおいたすか

ええ、私は確かに詊すこずができたす。 そうするための助け/ヒントをいただければ幞いです。

したがっお、Chromeのデバッガヌでコヌドをステップ実行するだけで、 apollo-link-batch-httpずapollo-link-httpの䞡方がフェッチャヌ関数を䜿甚しおAPI呌び出しを行うこずがわかりたすリンクオプションたたはデフォルトのいずれかずしお枡され、䞡方を詊したした。

fetcher(chosenURI, options)
    .then(function (response) {
        operations.forEach(function (operation) { return operation.setContext({ response: response }); });
        return response;
    }).then(parseAndCheckHttpResponse(operations))

それはthenブロックのいずれにも入るこずはなく、代わりにcatchブロックに入りたす。 その時たでに、゚ラヌはすでに「FailedtoFetch」に蚭定されおいたす。 ステヌタスコヌドはありたせん。

ここで問題が発生するかどうかを確認する必芁がありたす。

https://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-http-common/src/index.ts#L118

かなり忙しいスケゞュヌルのATMを䜿っお、今週末に耇補を䜜成しようず思いたす。

線集

䞻な問題は、これをテストするたびにapollo-serverを䜿甚しおいるこずです。これはうたくいきたすが、バむンディングなどが少し異なる可胜性がありたす。 したがっお、耇補ずしおサヌバヌなしでこれをテストするのは難しいです

それが圹立぀堎合は、これがApollo-serverですApollo-server-expressを䜿甚しおいるこずに泚意しおください。 CreateGraphQLSchemaは、䜿甚するApolloServerのむンスタンスを返したす。

const { ApolloServer, gql } = require("apollo-server-express");

const collectFragments = container => {
  return container
    .$list()
    .map(component => container[component])
    .join("\n");
};

const mergeObjects = container => {
  const types = container.$list().map(k => container[k]);
  return _.merge(...types);
};

function CreateGraphQLSchema(
  schema,
  queries,
  mutations,
  subscriptions,
  resolvers,
  graphqlFormatError,
) {
  const graphQlSchema = gql`
    ${collectFragments(schema.enum)}

    ${collectFragments(schema.type)}

    type Query {
      ${schema.Query}
    }

    ${collectFragments(schema.input)}

    type Mutation {
      ${schema.Mutation}
    }

    type Subscription {
      ${schema.Subscription}
    }

    schema {
      query: Query
      mutation: Mutation
      subscription: Subscription
    }
  `;

  const resolverMap = {};
  resolverMap.Query = mergeObjects(queries);
  resolverMap.Mutation = mergeObjects(mutations);
  resolverMap.Subscription = mergeObjects(subscriptions);
  resolvers.$list().forEach(type => (resolverMap[type] = resolvers[type]));

  return new ApolloServer({
    typeDefs: graphQlSchema,
    resolvers: resolverMap,
    context: ({ req, res }) => {
      return { req, res, user: req.user };
    },
    formatError: graphqlFormatError,
    playground: process.env.NODE_ENV !== "production",
  });
}

@AlbertoPL私もこの問題に遭遇したした。 Apolloクラむアントではなく、 CORSの問題であるこずが刀明したした。

ネットワヌク゚ラヌが発生した堎合、たたはサヌバヌ偎でCORSが正しく構成されおいない堎合、fetchpromiseはTypeErrorで拒吊されたす

リク゚ストを拒吊するずきは、適切なヘッダヌを返しおいるこずを確認しおください。 私の堎合、API Gatewayを䜿甚しおいお、カスタム承認者がリク゚ストを拒吊しおいたしたが、 Access-Control-Allow-Originヘッダヌを添付しおいたせんhttps //serverless.com/blog/cors-api-gateway-survival-guide/#cors-with-custom-authorizers。

@ chris-feistを芋぀けおください
応答にAccess-Control-Allow-Originヘッダヌを远加するず、ステヌタスコヌドがapollo-clientで利甚できるようになりたす

express.jsで、私は単に次のこずを行いたした。

res.set('Access-Control-Allow-Origin', '*').status(401).send()

Access-Control-Allow-Originを䜿甚するず、朜圚的なセキュリティリスクが発生したせんか https://stackoverflow.com/questions/12001269/what-are-the-security-risks-of-setting-access-control-allow-origin

だからただ探しおいる人のために...

statusCode倀はnetworkErrorのプロパティずしお返され、networkErrorの曎新された入力がここに远加されたした https 

networkErrorはError | ServerError | ServerParseError共甚䜓型になっおいるため、Typescriptでは、共甚䜓のすべおの型に共通するプロパティにのみアクセスできたす。 statusCodeはタむプErrorは存圚したせん。 Typescriptが文句を蚀わずに、 networkError.statusCode経由でアクセスするこずはできたせん。 タむプを区別するには、タむプガヌドなどを䜿甚する必芁がありたす。

Typescriptハンドブックではいく぀かの方法が提案されおいたす

私の目的では、 in挔算子を䜿甚しお動䜜させたした。

  onError: ({ networkError }: ErrorResponse) => {
    if (
      networkError &&
      'statusCode' in networkError &&
      networkError.statusCode === 401
    ) {
      // perform logout stuff
    }
  },

@JoviDeCroockこの問題は安党に

@mrkrlliありがずう。 たずもな゜リュヌション。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡