4. HTTP协议基础:请求方法、头信息与状态码

说实话,很多人学Socket编程时,一上来就撸代码。结果呢?连HTTP请求长什么样都没见过。我当年也是这样,写了个服务器,浏览器访问返回一堆乱码。后来才明白——不懂HTTP协议,写出来的服务器就是玩具。

这一章,咱们把HTTP协议的核心概念过一遍。你不需要背下所有细节,但得理解它的工作方式。毕竟,咱们后面要用Socket手写一个HTTP服务器,这些是地基。

4.1 HTTP请求方法:GET与POST

HTTP协议定义了多种请求方法。但说实话,日常开发中90%的场景只用两个:GET 和 POST。

4.1.1 GET方法

GET,说白了就是「我要拿东西」。浏览器输入网址回车,就是GET请求。它的特点是:

  • 参数在URL里:比如 ?name=zhangsan&age=25
  • 有长度限制:不同浏览器限制不同,一般2048字符左右
  • 会被缓存:浏览器会缓存GET请求的结果
  • 不安全:参数明文暴露在URL里

重要原则:GET请求只应该用来获取数据,不应该修改服务器状态。这是RESTful API的基本规范。

4.1.2 POST方法

POST就不同了。它是「我要提交东西」。登录、注册、上传文件,都用POST。特点如下:

  • 参数在请求体里:URL干干净净,数据在body里
  • 没有长度限制:理论上可以传任意大小的数据
  • 不会被缓存:每次都是新请求
  • 相对安全:参数不会暴露在URL里

我在项目中遇到过一个问题:有人用GET请求做删除操作。结果搜索引擎爬虫路过,把整个数据库删了……嗯,从那以后我再也不敢用GET做写操作了。

4.2 请求头与响应头

HTTP头信息,就像快递包裹上的标签。它告诉服务器「我是谁」「我要什么」「我的能力是什么」。同样,服务器也会在响应里告诉客户端「我返回了什么」「我的状态如何」。

4.2.1 常见请求头

请求头 含义 示例
Host 目标主机名和端口 Host: www.example.com:8080
User-Agent 客户端类型和版本 User-Agent: Mozilla/5.0 ...
Content-Type 请求体的MIME类型 Content-Type: application/json
Content-Length 请求体字节长度 Content-Length: 128
Accept 客户端能处理的响应类型 Accept: text/html, application/json
Cookie 客户端存储的会话信息 Cookie: session_id=abc123

个人习惯:调试HTTP请求时,我一般先看 Content-Type 和 Content-Length。这两个头不对,后面解析body肯定出问题。

4.2.2 常见响应头

响应头 含义 示例
Content-Type 响应体的MIME类型 Content-Type: text/html; charset=utf-8
Content-Length 响应体字节长度 Content-Length: 2048
Set-Cookie 设置客户端Cookie Set-Cookie: session_id=xyz; Path=/
Location 重定向目标URL Location: /new-page.html
Cache-Control 缓存策略 Cache-Control: no-cache

4.3 状态码:200、404、500

状态码是服务器给客户端的「回执」。三位数字,第一位数就决定了类别。我刚开始学的时候,记不住那么多状态码。后来发现,只要记住几个核心的,其他遇到再查就行。

4.3.1 状态码分类

分类 范围 含义 常见例子
1xx 100-199 信息性响应 100 Continue
2xx 200-299 成功 200 OK
3xx 300-399 重定向 301 Moved Permanently
4xx 400-499 客户端错误 404 Not Found
5xx 500-599 服务器错误 500 Internal Server Error

4.3.2 三个核心状态码

200 OK:一切正常。请求成功,响应体里就是你要的数据。这是最理想的状态。

404 Not Found:资源不存在。你想想看,用户访问了一个不存在的页面,或者图片路径写错了,就会返回404。我曾经排查过一个线上问题,页面白屏,结果是因为CSS文件路径写错了,返回了404。

500 Internal Server Error:服务器内部错误。这是最让人头疼的。代码抛异常了、数据库连不上了、内存溢出了……都会返回500。我建议你在开发阶段,把服务器错误信息打印到日志里,而不是直接返回给客户端。

避坑指南:千万不要在生产环境返回500时附带详细的堆栈信息。这等于把服务器的弱点暴露给攻击者。我曾经见过一个网站,500页面直接打印了SQL语句……嗯,后果你懂的。

4.4 HTTP/1.1 vs HTTP/2.0

这两个版本的区别,说白了就是「单车道」和「多车道」的区别。咱们用Socket编程时,默认实现的是HTTP/1.1。但理解HTTP/2.0的改进,能帮你写出更高效的服务器。

4.4.1 HTTP/1.1的特点

  • 持久连接:默认开启 Connection: keep-alive,一个TCP连接可以发送多个请求
  • 管道化:可以连续发送多个请求,但响应必须按顺序返回(队头阻塞)
  • 文本协议:请求和响应都是明文文本,人类可读
  • 头部未压缩:每次请求都携带完整的头部信息

4.4.2 HTTP/2.0的改进

  • 二进制分帧:数据被拆分成更小的帧,可以交错传输
  • 多路复用:一个TCP连接可以同时处理多个请求,没有队头阻塞
  • 头部压缩:使用HPACK算法压缩头部,减少传输量
  • 服务器推送:服务器可以主动推送资源给客户端
特性 HTTP/1.1 HTTP/2.0
数据格式 文本 二进制
多路复用 不支持(有队头阻塞) 支持
头部压缩 不支持 支持(HPACK)
服务器推送 不支持 支持
连接复用 支持(keep-alive) 支持(更高效)

我的建议:用Socket实现HTTP服务器时,先实现HTTP/1.1。它简单、直观、容易调试。等你把1.1玩透了,再考虑支持HTTP/2.0。毕竟,咱们的目标是理解底层原理,不是造一个生产级的服务器。

4.5 本章知识体系

下面这张图,把本章的核心知识点串起来了。你仔细看看,HTTP请求从客户端发出,经过服务器解析,最后返回响应——整个过程就是这些组件在协作。

HTTP协议核心知识体系 客户端(浏览器) 请求方法 GET / POST 请求头 Host / Content-Type 服务器 状态码 200 / 404 / 500 响应头 Content-Type / Set-Cookie HTTP版本对比 HTTP/1.1:文本、队头阻塞 HTTP/2.0:二进制、多路复用 头部压缩、服务器推送 核心要点 GET获取数据 POST提交数据 200成功 / 404不存在 500服务器错误

你看,整个流程其实不复杂。客户端发起请求(GET或POST),带上请求头。服务器收到后,解析请求,处理业务逻辑,然后返回状态码和响应头。最后把数据塞进响应体,发给客户端。

咱们后面用Socket实现HTTP服务器时,就是在手动完成这个过程。你理解了这些基础,写代码的时候心里就有底了。