首页 > 解决方案 > 如何在 JavaScript 中进行简单的 GraphQL 查询

问题描述

如果我使用 e 进行 GraphQL 查询,node-fetch或者curl我得到预期的结果。例如,如果我有一个包含以下代码的文件gquery.js :

const fetch = require("node-fetch")
fetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-Api-Service-Key': '123456789077',
  },
  body: JSON.stringify({query: "query($fruitId: String!) { fruit(id: $fruitId) { id, name } }",
  variables: { "fruitId": "ikttwwwbvn7" }})
})
  .then(r => r.json())
  .then(data => console.log('data returned:', data));

在我的 Ubuntu 机器上,我刚刚运行$node gquery.js我得到了一个结果。如果我使用普通卷曲,我也会得到一个结果,例如:

curl -H 'Content-Type: application/json' -X POST -H "X-Api-Service-Key: 123456789077" https://api.example.com/graphql -d '{ "query": "query($fruitId: String!) { fruit(id: $fruitId) { id, name } }", "variables": { "fruitId": "ikttwwwbvn7" }}'

但是,如果我只是在 Chrome 上使用fetch ,例如:

fetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-Api-Service-Key': '123456789077',
  },
  body: JSON.stringify({query: "query($fruitId: String!) { fruit(id: $fruitId) { id, name } }",
  variables: { "fruitId": "ikttwwwbvn7" }})
})
  .then(r => r.json())
  .then(data => console.log('data returned:', data));

我收到一个错误:

CORS 策略已阻止从源“chrome-search://local-ntp”访问“ https://api.example.com/graphql ”获取:对预检请求的响应未通过访问控制检查:否请求的资源上存在“Access-Control-Allow-Origin”标头。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

注意:我的端点实际上是不同的,但除此之外,此示例与我的示例基本相同。

我看了一个相关的问题,但答案似乎表明这不能仅在客户端解决。curl但我可以使用并成功的事实node告诉我,我只是没有正确的代码。

说清楚,我真的不在乎fetch。我很乐意使用任何不需要使用像 apollo 或 relay 这样的客户端的独立 Javascript 解决方案。

标签: javascriptgraphql

解决方案


没有办法绕过浏览器强制执行的同源策略。通过发送请求时您不会遇到相同的问题,curl或者node因为在这些上下文中未强制执行同源策略。除非您明确禁用它,否则它始终在浏览器中强制执行。但是,防止跨域请求是一种导入安全措施,因此通常不建议禁用它。

像 Apollo 这样的 GraphQL 客户端的工作方式并没有什么神奇之处。他们仍然fetch在引擎盖下使用。如果您在使用 fetch 时遇到了 CORS 问题,那么您会在使用 Apollo 或任何其他基于浏览器的客户端时遇到同样的问题。如果您使用 Postman 或 Altair 之类的独立客户端,则不会,因为您再次处理的不是浏览器。

正如您链接的帖子中所建议的那样,这是一个必须在服务器端解决的问题。如果您不向自己的服务器发出请求,唯一可行的解​​决方法是使用代理。您可以使用现有的或运行自己的。


推荐阅读