改用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
相关产品推荐
相关产品推荐

