我有一个突变请求,成功时会以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_,因为没有响应,但是如果没有任何响应字段,那么我再也不能发送突变……除非我丢失了某些内容。
@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-Type
是application/json
下解析JSON,但是也可以想象某些API可能将所有响应甚至在空204响应中都设置为相同的标头。
由于剩余链接会在高于300的任何状态码上产生networkError
,因此响应解析只需要足够的专门知识即可正确处理2xx状态码。 人们可能会合理地期望遇到的是:
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
标头。
最有用的评论
我认为,为了使空主体的上游GraphQL解释起作用,我们应该返回
{}
,这将导致当您说“可以同时支持两种行为吗?” 您的意思是查看204状态码并查看标题吗? 我猜想当
Content-Length
实际上存在并且0
然后存在时,我们可以将其作为另一个空体的指示并返回默认值。尽管我早些时候提出了
Content-Type
标头,但实际上我不清楚将其设置为json
以外的其他方法时应该做什么。 我认为,如果要解释此标头,则可能需要使用与建议的bodySerializer
类似的responseSerializer
配置选项来完成。 但是,这可能是过大的,并且不会特别解决空体问题。我很高兴执行204和Content-Length的实现。