规范与传输
GraphQL 规范与 HTTP。
25 分钟
规范与传输
这一课你将能做到
- 构造一个完全合规的 GraphQL over HTTP 请求,说清每个 header 与 body 字段的作用
- 根据返回的 HTTP 状态码 +
Content-Type判断失败发生在哪个阶段 - 讲清 graphql-response+json 媒体类型、GET/POST 分工与增量交付的传输格式
为什么要学
「GraphQL 永远返回 200」是流传最广的半真半假的说法。老实现确实如此,但 GraphQL over HTTP 规范(2023 年起成为官方规范的一部分) 重新规定了状态码语义:解析错误 400、校验错误 400、未认证 401、执行错误仍可 200。不理解这一层,你的网关、重试逻辑、监控告警都会基于错误假设搭建。
人话:GraphQL 只管「文档怎么写、结果怎么算」,HTTP 规范管「文档怎么寄、信封上盖什么章」。
先建立图像
请求信封的完整结构:
POST /graphql HTTP/1.1
Host: api.example.com
Content-Type: application/json ← body 的格式
Accept: application/graphql-response+json ← 期望的响应格式(现代)
Authorization: Bearer eyJhbGciOi... ← 鉴权(协议无关)
{
"query": "query Q($slug: String!) { lesson(slug: $slug) { title } }",
"operationName": "Q",
"variables": { "slug": "gqlrm-spec" },
"extensions": { "persistedQuery": { "version": 1, "sha256Hash": "..." } }
}
状态码决策树:
请求到达
├─ body 不是合法 JSON? → 400
├─ query 缺失 / 语法错误? → 400
├─ 校验失败(字段不存在等)? → 400(现代规范)
├─ 未认证 / 无权限整个操作? → 401 / 403
├─ GET 发了 mutation? → 405
└─ 执行期错误(resolver 抛错) → 200 + { data(部分), errors }
跟着做
步骤 1:用 curl 走一遍现代规范请求
curl -i http://localhost:8080/graphql \
-H "Content-Type: application/json" \
-H "Accept: application/graphql-response+json" \
-d '{
"query": "query Ping { lesson(slug: \"gqlrm-spec\") { title } }",
"operationName": "Ping"
}'
观察响应头:Content-Type: application/graphql-response+json; charset=utf-8。这就是 IANA 注册的官方媒体类型,区别于老的 application/json。
步骤 2:GET 请求做纯查询(可缓存场景)
规范允许 GET 承载无副作用的 query(不允许 mutation):
curl -i "http://localhost:8080/graphql?query=%7B%20lesson(slug%3A%5C%22gqlrm-spec%5C%22)%20%7B%20title%20%7D%20%7D&operationName=X"
query/variables/extensions 都放 URL 参数(URL 编码)。意义:GET 响应理论上可被 CDN/浏览器按 HTTP 缓存语义缓存——这是 GraphQL 蹭 HTTP 缓存的唯一通道。
步骤 3:分别制造三类失败,看状态码
# ① 语法错误 → 400
curl -s -o /dev/null -w "%{http_code}\n" -X POST localhost:8080/graphql \
-H "Content-Type: application/json" -d '{"query":"{ lesson("}'
# ② 校验错误 → 400(现代实现)
curl -s -o /dev/null -w "%{http_code}\n" -X POST localhost:8080/graphql \
-H "Content-Type: application/json" -d '{"query":"{ notExistField }"}'
# ③ 执行错误 → 200 + errors
curl -s -X POST localhost:8080/graphql \
-H "Content-Type: application/json" -d '{"query":"{ lesson(slug:\"no-such\") { title } }"}'
# → HTTP 200, {"data":{"lesson":null}} 或带 errors,视 Schema 可空性