Apollo-link-rest: REST响应为空时出错

创建于 2018-05-07  ·  18评论  ·  资料来源: apollographql/apollo-link-rest


我有一个突变请求,成功时会以204“无内容”状态响应。 当与apollo-link-error结合使用时,我不断收到网络错误: JSON input意外结束

似乎apollo-link-rest正在尝试解析响应的空白内容。

有什么想法可以减轻这种情况吗? 顺便说一句,我正在尝试与SharePoint REST api通讯,所以我没有太多可以调整服务器的响应的了。

应该有一种方法告诉apollo-link-rest如何处理空响应...

我的变异电话:

                  <Mutation mutation={M_WRITE_PROJECT_DETAILS}>
                    {(writeProjectDetails, { data }) => (
                      <Form.Button
                        content="Save"
                        onClick={() => {
                          const token = localStorage.getItem("token");
                          writeProjectDetails({
                            variables: {
                              projectId: project.Id,
                              input: {
                                __metadata: {
                                  type: "SP.Data.ProjectListItem"
                                },
                                Title: project.Title
                              }
                            },
                            context: {
                              headers: {
                                "X-RequestDigest": token,
                                "X-HTTP-Method": "MERGE",
                                "IF-MATCH": "*"
                              }
                            }
                          });
                        }}
                      />
                    )}
                  </Mutation>

相应的gql查询:

const M_WRITE_PROJECT_DETAILS = gql`
  mutation writeToSPList($projectId: String, $input: String) {
    writeToSPList(projectId: $projectId, input: $input)
      @rest(
        type: "Project"
        path: "/web/lists/GetByTitle('Projects')/items(:projectId)"
        method: "POST"
      ) {
      NoResponse
    }
  }
`;

“ NoResponse”显然是_null_,因为没有响应,但是如果没有任何响应字段,那么我再也不能发送突变……除非我丢失了某些内容。

enhancement💡 feature help wanted 🛠 question❔

最有用的评论

我认为,为了使空主体的上游GraphQL解释起作用,我们应该返回{} ,这将导致

data: {
  __typename: "...",
  NoResponse: null,
}

当您说“可以同时支持两种行为吗?” 您的意思是查看204状态码并查看标题吗? 我猜想当Content-Length实际上存在并且0然后存在时,我们可以将其作为另一个空体的指示并返回默认值。

尽管我早些时候提出了Content-Type标头,但实际上我不清楚将其设置为json以外的其他方法时应该做什么。 我认为,如果要解释此标头,则可能需要使用与建议的bodySerializer类似的responseSerializer配置选项来完成。 但是,这可能是过大的,并且不会特别解决空体问题。

我很高兴执行204和Content-Length的实现。

所有18条评论

@isopterix-我认为我们现在没有真正简单的方法来处理此问题。 -我最初的想法是建议您包装Fetch并提供一个自定义Fetch实现,用{}代替204个响应的主体-我认为如果没有构建更好的功能,那是我可以做到这一点的唯一方法今天!

@isopterix我尝试通过以下测试重现此问题,但该测试通过了一个空的身体。 看起来当主体为空字符串时,获取response.json()返回{} 。 您是否可以尝试在实时设置中更仔细地跟踪此错误,以查看发生错误的位置?

  describe('response parsing', () => {
    it('supports empty response bodies', async () => {
      expect.assertions(1);

      const link = new RestLink({ uri: '/api' });

      fetchMock.post('/api/posts', {
        status: 204,
        body: '',
      });

      const mutation = gql`
        mutation postEmptyResponse($input: String!) {
          newPost(input: $input)
            @rest(type: "Post", path: "/posts", method: "POST") {
            NoResponse
          }
        }
      `;
      const {data} = await makePromise<Result>(
        execute(link, {
          operationName: 'postEmptyResponse',
          query: mutation,
          variables: { input: 'Love apollo' },
        }),
      );

      expect(data).toEqual({
        newPost: {
          NoResponse: null,
          __typename: 'Post',
        }
      });
    });
  });

@isopterix不用介意我的最后评论。 似乎浏览器的实现比测试环境要宽容得多。

我发现检测到一个空的主体时遇到的一个问题是,如果不调用res.json()res.text() ,并且始终以防万一也调用它们,则无法确定该主体中的内容多余的。 否则,可能会查看Content-Length标头,但我不太确定它是否始终可靠。 另一种选择是仅在Content-Typeapplication/json下解析JSON,但是也可以想象某些API可能将所有响应甚至在空204响应中都设置为相同的标头。

由于剩余链接会在高于300的任何状态码上产生networkError ,因此响应解析只需要足够的专门知识即可正确处理2xx状态码。 人们可能会合理地期望遇到的是:

  • 200 OK
  • 创建了201
  • 202接受
  • 204没有内容
  • (还有其他人吗?)

204条回应应该是唯一没有任何回应的回应。 是否可以选择检查状态码并在默认值为204时返回默认的{} ? 虽然这将是针对特定边缘情况的测试,但它将使该库更符合HTTP标准,这似乎是一件好事。

@fbartho您对这些方法之一有什么偏好吗? 如果这些选项之一或其组合听起来合理,我将做PR。

也许这里有一条中间道路? 两种行为都可以支持吗?

我非常支持默认情况下自己将204解释为{},或者说“ null”是否为null语义等同于JSON中没有内容?

我认为,为了使空主体的上游GraphQL解释起作用,我们应该返回{} ,这将导致

data: {
  __typename: "...",
  NoResponse: null,
}

当您说“可以同时支持两种行为吗?” 您的意思是查看204状态码并查看标题吗? 我猜想当Content-Length实际上存在并且0然后存在时,我们可以将其作为另一个空体的指示并返回默认值。

尽管我早些时候提出了Content-Type标头,但实际上我不清楚将其设置为json以外的其他方法时应该做什么。 我认为,如果要解释此标头,则可能需要使用与建议的bodySerializer类似的responseSerializer配置选项来完成。 但是,这可能是过大的,并且不会特别解决空体问题。

我很高兴执行204和Content-Length的实现。

到目前为止,我遵循了先前的建议,并实现了自定义抓取来处理204响应。 但是我很难得到适当的回应。 可以选择立即使用此功能,真是太棒了。

不幸的是,我仍在学习如何导航JS世界...

已通过#111修复!

甜的! 非常感谢你。

现在,只剩下一个小问题了:)在我制定了自己的临时解决方案后,我又遇到了目标SharePoint Server的REST API的另一个问题...如果删除条目,则会收到200条响应没有身体内容:)

我们是否可以将行为概括化,即,如果没有正文内容使用“ NoResponse”标签进行响应? 如果我没有记错的话,该补丁当前仅解决204特殊情况。

@isopterix如果服务器将Content-Length正确地设置为零,则即使对200个响应也应该可以工作,目的也是要检查该响应。

期待它可以旋转。

这是否涵盖任何内容为空的成功响应? 像没有内容的200?

是的。 为此合并的修复程序检查204状态或Content-Length: 0标头并返回一个空对象。

如果您有200个空响应而没有Content-Length标头,则该响应将不起作用,因为未对此检查进行解析。

@isopterix您可以确认这有效吗? 我正在尝试做一个突变,使我的状态为200和Content-Length: 0 。 但是,我仍然得到Network error: Unexpected end of JSON input 。 我正在使用版本0.7.0。

我看到调试apollo-link-rest时响应标头为空,而我的浏览器实际上显示的是标头。 apollo-link-rest操纵/重置响应对象中的标头?

Apollo-link-rest不操纵响应头@dljcollette! 希望能有所帮助

我遇到同样的错误

空状态为200的情况有什么解决方法?

@thomaszdxsn容纳这种情况的唯一方法是使用res.text()而不是res.json()并在使用JSON.parse()解析之前检查有效的JSON。 这意味着您无需进行流式JSON解析,因此不可能完成。

最好的解决方案是更改您的API,以便在主体为空时使用语义正确的状态代码204,或者在200响应主体中返回某些内容。 我认为,只要响应主体中只有有效的JSON,即使是空的JSON编码对象也可以使用。

如果您确实无法更改API,则可以将自定义fetch函数传递给apollo-link-rest ,您可以检查并更改响应,然后最终返回ALR进行处理。 这将是一个hack,但它可能对您有用。

或者,再次确保API在响应中返回Content-length: 0标头。

此页面是否有帮助?
0 / 5 - 0 等级