You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

改用graphql-http搭建GraphQL服务后出现415状态码问题求助

解决graphql-HTTP搭配原生Node.js HTTP服务器时的415状态码问题

发现express-graphql已被弃用,改用官方推荐的graphql-HTTP实现GraphQL服务,但在浏览器中请求时返回415状态码,尝试添加charset请求头后问题仍未解决。以下是我的代码:

server.js

import { createHandler } from "graphql-http/lib/use/express";
import { buildSchema } from "graphql";
import http from "http";
import fs from "fs";
import path from "path";

const __filename = new URL(import.meta.url).pathname;
const __dirname = path.dirname(__filename);

const PORT = 4000;

var schema = buildSchema(
  `
    type Query {
        hello: String
    }
    `
);

const root = {
  hello: () => {
    return "Hello, world!";
  },
};
const handler = createHandler({ schema, rootValue: root });

const server = http.createServer((req, res) => {
  if (req.url.startsWith("/graphql")) {
    if (req.method === "OPTIONS") {
      res.writeHead(200, {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "OPTIONS, POST",
        "Access-Control-Allow-Headers": "Content-Type",
      });
      res.end();
      return;
    }

    if (req.method === "POST") {
      handler(req, res);
    } else if (req.method === "GET") {
      const htmlContent = `
        <!DOCTYPE html>
        <html lang="en">
        <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Simple Page</title>
        </head>
        <body>
          <h1>Hello, World!</h1>
        </body>
        </html>
      `;

      res.writeHead(200, { "Content-Type": "text/html" });
      res.end(htmlContent);
    }
  } else {
    res.writeHead(404).end();
  }
});

server.listen(PORT);
console.log(`Listening on port ${PORT}`);

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GraphQL Test</title>
</head>

<body>
  <script>
    // Simple GraphQL query using fetch
    fetch('http://localhost:4000/graphql', {
        method: 'POST',
        mode: 'no-cors',
        headers: {
          'Content-Type': 'application/json; charset=urf8',
        },
        body: JSON.stringify({
          query: `
          query {
            hello
          }
        `,
        }),
      })
      .then(response => response.json())
      .then(data => console.log('GraphQL Response:', data))
      .catch(error => console.error('Error:', error));
  </script>
</body>

</html>

问题原因及解决方案

1. 核心错误:使用了错误的graphql-HTTP适配器

你导入的是适配Express框架的createHandler,但实际使用的是原生Node.js HTTP服务器,两者的请求/响应对象结构不同,导致graphql-HTTP无法正确解析请求,返回415状态码。

修正方法:将导入路径改为原生Node.js适配器:

// 替换原导入语句
import { createHandler } from "graphql-http/lib/use/node";

2. 请求头拼写错误

index.html中Content-Type的charset值拼写错误:urf8应为utf8,这会导致服务器无法正确识别请求体格式。

修正方法:修正请求头:

headers: {
  'Content-Type': 'application/json; charset=utf8',
},

3. 错误使用no-cors模式

mode: 'no-cors'会让浏览器限制请求的响应处理,无法解析JSON格式的响应,同时会隐藏真实的错误信息。

修正方法:移除该配置(默认模式为cors,支持跨域请求):

fetch('http://localhost:4000/graphql', {
    method: 'POST',
    // 移除 mode: 'no-cors'
    headers: {
      'Content-Type': 'application/json; charset=utf8',
    },
    // ... 其他代码
})

4. 完善CORS响应头

当前仅在OPTIONS请求中添加了CORS头,POST请求的响应缺少Access-Control-Allow-Origin,会导致浏览器拦截响应。

修正方法:在处理POST请求时添加响应头:

if (req.method === "POST") {
  // 添加CORS响应头
  res.setHeader('Access-Control-Allow-Origin', '*');
  handler(req, res);
}

修正后的完整代码

修正后的server.js

import { createHandler } from "graphql-http/lib/use/node";
import { buildSchema } from "graphql";
import http from "http";
import path from "path";

const __filename = new URL(import.meta.url).pathname;
const __dirname = path.dirname(__filename);

const PORT = 4000;

var schema = buildSchema(
  `
    type Query {
        hello: String
    }
    `
);

const root = {
  hello: () => {
    return "Hello, world!";
  },
};
const handler = createHandler({ schema, rootValue: root });

const server = http.createServer((req, res) => {
  if (req.url.startsWith("/graphql")) {
    if (req.method === "OPTIONS") {
      res.writeHead(200, {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "OPTIONS, POST",
        "Access-Control-Allow-Headers": "Content-Type",
      });
      res.end();
      return;
    }

    if (req.method === "POST") {
      res.setHeader('Access-Control-Allow-Origin', '*');
      handler(req, res);
    } else if (req.method === "GET") {
      const htmlContent = `
        <!DOCTYPE html>
        <html lang="en">
        <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Simple Page</title>
        </head>
        <body>
          <h1>Hello, World!</h1>
        </body>
        </html>
      `;

      res.writeHead(200, { "Content-Type": "text/html" });
      res.end(htmlContent);
    }
  } else {
    res.writeHead(404).end();
  }
});

server.listen(PORT);
console.log(`Listening on port ${PORT}`);

修正后的index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GraphQL Test</title>
</head>

<body>
  <script>
    // Simple GraphQL query using fetch
    fetch('http://localhost:4000/graphql', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json; charset=utf8',
        },
        body: JSON.stringify({
          query: `
          query {
            hello
          }
        `,
        }),
      })
      .then(response => response.json())
      .then(data => console.log('GraphQL Response:', data))
      .catch(error => console.error('Error:', error));
  </script>
</body>

</html>

现在启动服务器,访问index.html,就能在控制台看到正确的响应{ data: { hello: "Hello, world!" } }。

内容的提问来源于stack exchange,提问作者Mathew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:23:10