🧱 一、从 TCP 三次握手到访问网页:两层过程
🧩 1. TCP 三次握手(网络传输层)
这是 建立连接 的前提,跟 HTTP 无关,但 HTTP 要依赖它。
举例:你打开浏览器访问 https://example.com
,首先浏览器会:
- DNS 解析 :把
example.com
变成 IP 地址,比如93.184.216.34
。 - TCP 三次握手 :
- 客户端 → 服务器:发送 SYN
- 服务器 → 客户端:返回 SYN-ACK
- 客户端 → 服务器:返回 ACK
- 至此,TCP 连接建立,后续数据就可以可靠地收发了。
🌐 2. HTTP 请求/响应(应用层)
TCP 建好连接后,才开始发送 HTTP 请求,浏览器会构造一个请求报文:
例如一个 HTTP GET 请求可能是这样的:
GET /index.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0)
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
📌 你提到的"扫描请求头的某些东西",其实就是服务器收到 HTTP 请求后会查看请求头中这些字段,比如:
- Host:确定你访问的是哪个站点(尤其在一台服务器上部署了多个网站时)
- User-Agent:知道你用的是浏览器还是爬虫、什么设备
- Accept / Content-Type:决定返回 HTML、JSON、图片还是别的格式
- Cookie / Authorization:判断你是否已登录、权限是否足够
🔍 所以你记得的"扫描"是指服务器读取这些请求头来决定如何处理请求,甚至是否允许访问。
🔄 整个访问过程一图理解
你输入网址 → DNS 解析 → TCP 三次握手 → HTTP 请求发送
↓ ↓
IP地址确定 建立连接(握手)
↓
浏览器发 HTTP 请求
↓
服务器读取请求头,决定响应
↓
HTTP 响应返回内容
↓
浏览器渲染网页
🔒 那 HTTPS 呢?
如果你访问的是 https://
:
- 在 TCP 三次握手之后,还要走一个 TLS 握手(加密协商)
- 成功后才会开始真正的 HTTP 请求(现在是 加密后的 HTTPS 请求)
✅ 总结你记得的"扫描请求头"的部分
你记得的没错,只是:
过程 | 你记得的细节 | 属于哪一层 | 是否"扫描" |
---|---|---|---|
TCP 三次握手 | 建立连接(三包) | 网络层 | ❌ 不看应用内容 |
HTTP 请求 | 请求头(Host、User-Agent 等) | 应用层 | ✅ 服务器会检查这些字段 |
HTTPS | 加密握手(TLS) | 网络 + 安全层 | ❌ 请求头被加密,不能被中间人看 |
下面是一个典型的完整 HTTP 请求头 ,以浏览器访问 https://www.example.com/index.html
为例,我们使用 GET
方法:
📥 示例:HTTP GET 请求头
GET /index.html HTTP/1.1
Host: www.example.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: session_id=abc123; theme=dark
🧩 各字段解释
字段名 | 含义 |
---|---|
GET /index.html HTTP/1.1 | 请求方法 + 路径 + HTTP 版本 |
Host | 当前请求目标的域名(多个虚拟主机时必须) |
Connection | 设置 TCP 连接策略,keep-alive 表示复用连接 |
Cache-Control | 控制是否使用缓存,这里表示不使用缓存 |
Upgrade-Insecure-Requests | 表示浏览器希望从 HTTP 自动升级为 HTTPS |
User-Agent | 表示用户的浏览器、操作系统等信息,服务器可能基于此做响应适配 |
Accept | 浏览器希望接受的响应内容类型 |
Accept-Encoding | 接受哪种压缩格式的响应内容(比如 gzip) |
Accept-Language | 浏览器接受的语言偏好 |
Cookie | 客户端存储的 cookie 数据,用于会话管理、个性化设置等 |
🔒 如果是 HTTPS 呢?
- 这些请求头内容是一样的,只不过在 HTTPS 下会经过加密,在网络上传输时是不可见的。
- 中间人(如 WiFi 路由器)不能读取里面的请求内容(包括头和 body)。
✅ 示例:使用 curl
模拟访问网页(带自定义请求头)
我们来模拟一个访问 https://www.example.com/index.html
的请求,并加上一些常见的请求头:
curl -X GET https://www.example.com/index.html \
-H "Host: www.example.com" \
-H "Connection: keep-alive" \
-H "Cache-Control: max-age=0" \
-H "Upgrade-Insecure-Requests: 1" \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" \
-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8" \
-H "Accept-Encoding: gzip, deflate, br" \
-H "Accept-Language: zh-CN,zh;q=0.9" \
-H "Cookie: session_id=abc123; theme=dark" \
-v
📌 说明:
-X GET
明确使用 GET 方法(其实默认就是 GET)。-H
用来设置每一条请求头。-v
表示 verbose 模式,可以显示请求和响应的详细信息(推荐开启!)。
🧪 运行效果(简略版)
运行后你会看到 curl
打印出如下内容:
> GET /index.html HTTP/1.1
> Host: www.example.com
> Connection: keep-alive
> Cache-Control: max-age=0
> Upgrade-Insecure-Requests: 1
> User-Agent: Mozilla/5.0 ...
> Accept: text/html,...
> Accept-Encoding: gzip, deflate, br
> Accept-Language: zh-CN,zh;q=0.9
> Cookie: session_id=abc123; theme=dark
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Content-Encoding: gzip
< Content-Length: ...
...
你会看到:
- 上半部分是你发出的请求(带请求头)
- 下半部分是服务器的响应(状态码、响应头、响应体)
✅ 实战建议
你可以把上面的命令复制到终端执行,只要换一个真实的网址,比如:
curl -X GET https://www.baidu.com \
-H "User-Agent: CustomClient/1.0" \
-H "Accept: application/json" \
-H "Cookie: session_id=xyz999" \
-v
PS C:\Users\33895> curl.exe https://httpbin.org/get -H "User-Agent: TestUA" -v
* Host httpbin.org:443 was resolved.
* IPv6: (none)
* IPv4: 198.17.0.206
* Trying 198.17.0.206:443...
* schannel: disabled automatic use of client certificate
* ALPN: curl offers http/1.1
* ALPN: server accepted http/1.1
* Connected to httpbin.org (198.17.0.206) port 443
* using HTTP/1.x
> GET /get HTTP/1.1
> Host: httpbin.org
> Accept: */*
> User-Agent: TestUA
>
* Request completely sent off
< HTTP/1.1 503 Service Temporarily Unavailable
< Server: awselb/2.0
< Date: Thu, 01 May 2025 14:43:13 GMT
< Content-Type: text/html
< Content-Length: 162
< Connection: keep-alive
<
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
</body>
</html>
* Connection #0 to host httpbin.org left intact
PS C:\Users\33895>
🔍 命令行回顾
curl.exe https://httpbin.org/get -H "User-Agent: TestUA" -v
curl.exe
: 使用的是 Windows 系统内置的原始 curlhttps://httpbin.org/get
: 请求的目标 URL(GET 请求)-H "User-Agent: TestUA"
: 添加自定义请求头-v
: verbose 模式,打印详细连接与通信过程
🧾 输出详解
🔹 1. DNS解析 & TCP连接
* Host httpbin.org:443 was resolved.
-
说明已通过 DNS 查到
httpbin.org
的 IP 地址,并准备连接 443 端口(HTTPS)- IPv6: (none)
- IPv4: 198.17.0.206
-
目标主机没有 IPv6 地址,使用 IPv4
198.17.0.206
- Trying 198.17.0.206:443...
-
正在尝试与该 IP 的 443 端口建立 TCP 连接
🔹 2. TLS/SSL & ALPN 协议协商
* schannel: disabled automatic use of client certificate
-
schannel
是 Windows 下的 TLS/SSL 库,这里说明未使用客户端证书(默认行为)- ALPN: curl offers http/1.1
- ALPN: server accepted http/1.1
-
ALPN(Application-Layer Protocol Negotiation)是 TLS 的扩展
-
表示 curl 提议使用 HTTP/1.1,服务器也接受了
🔹 3. TCP连接成功
* Connected to httpbin.org (198.17.0.206) port 443
* using HTTP/1.x
- TCP + TLS 握手成功,连接已建立
- 使用 HTTP/1.x 协议
🔹 4. 请求发送
> GET /get HTTP/1.1
> Host: httpbin.org
> Accept: */*
> User-Agent: TestUA
-
GET /get HTTP/1.1
: 请求的方法、路径和协议 -
Host: httpbin.org
: 指定目标主机(必需) -
Accept: */*
: 表示接受任意响应类型 -
User-Agent: TestUA
: 你自定义的 UA 标识头- Request completely sent off
-
表示请求已经完全发送出去
🔹 5. 响应返回
< HTTP/1.1 503 Service Temporarily Unavailable
< Server: awselb/2.0
< Date: Thu, 01 May 2025 14:43:13 GMT
< Content-Type: text/html
< Content-Length: 162
< Connection: keep-alive
HTTP/1.1 503
: 服务器返回的响应状态码(临时不可用)Server: awselb/2.0
: 服务器是 AWS 的 Elastic Load BalancerDate
: 响应时间Content-Type
: 返回的是 HTML(网页),不是 JSONContent-Length
: HTML 内容的长度(162 字节)Connection: keep-alive
: 服务器希望保持连接,不马上断开
🔹 6. 响应正文
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
</body>
</html>
- 简单的 HTML 页面,提示 503 错误
🔹 7. 连接结束
* Connection #0 to host httpbin.org left intact
- 表示连接未关闭(keep-alive 生效),curl 不会主动断开,供下次复用
✅ 总结
这个 verbose 输出涵盖了:
阶段 | 内容 |
---|---|
DNS解析 | 查到 IP 地址 |
TCP连接 | 与服务器建立连接 |
TLS握手 | 通过 ALPN 确定使用 HTTP/1.1 |
请求内容 | 打印发出的 HTTP 请求头 |
响应头 | 打印服务器返回的响应状态和内容类型 |
响应体 | HTML 错误页 |
连接处理 | 保持连接未关闭 |
PS C:\Users\33895> curl.exe "https://www.baidu.com/s?wd=test"
<a href="https://wappass.baidu.com/static/captcha/tuxing_v2.html?&logid=7987820460167506860&ak=c27bbc89afca0463650ac9bde68ebe06&backurl=https%3A%2F%2Fwww.baidu.com%2Fs%3Fwd%3Dtest&ext=x9G9QDmMXq%2FNo87gjGO0P7zYlbLsT8y8wKbl0sIMQh9WkhrGqVqihBVl6ZY8QtPHUgqUK9LXd1cIlztrhMwiv5LGqKWhTZD8Q7xZpGkscD5m9BVI2WSf6oW03O5A8dkk&signature=b7d7e5b0fc3623b54c550ff291d55c76&timestamp=1746111289">Found</a>.
你这个请求遇到了百度的 反爬虫/验证码重定向机制。我们来逐步解析发生了什么:
📌 现象说明:
你访问的是:
bash
复制编辑
curl.exe "https://www.baidu.com/s?wd=test"
返回的内容却是这样的一段:
html
复制编辑
<a href="https://wappass.baidu.com/static/captcha/tuxing_v2.html?...">Found</a>.
这说明:
✅ 百度确实返回了 302 重定向(跳转到验证码页面):
- 当百度认为你的请求不是"真实用户"发起的(比如没有浏览器行为、没有 cookies、没有 JS 执行环境),它会:
- 返回一个 302 重定向
- 重定向目标是一个图形验证码页面,提示你要"点点验证码"验证你是人类
🔍 为什么你会被拦?
百度会检测以下条件:
检测点 | 描述 |
---|---|
User-Agent | 是否是常见浏览器 |
Referer | 是否从网页点击过来的 |
Cookie | 有没有已有的身份信息(如百度登录或搜索行为) |
JS行为 | 是否会执行 JavaScript,返回行为数据(curl 不会) |
✅ 如何"伪装浏览器"避免被立即拦?
你可以模拟常见浏览器的请求头,比如:
bash复制编辑curl.exe "https://www.baidu.com/s?wd=test" ^
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/122.0.0.0 Safari/537.36" ^
-H "Accept: text/html" ^
-H "Referer: https://www.baidu.com" ^
-H "Accept-Language: zh-CN,zh;q=0.9" ^
-L ^
-v
参数说明:
-H
: 模拟请求头-L
: 自动跟随重定向(避免只看到 302)-v
: 查看详细过程
⚠️ 即便如此,百度仍然可能返回验证码页面,因为它用 JS + 图形验证码判断你是不是"机器人"。
✅ 正确调试方式建议:
如果你只是想学习和调试 HTTP 请求:
- 使用
httpbin.org
、httpbingo.org
、reqres.in
这类测试服务器 - 或自己搭个简单 Flask/FastAPI 服务,方便测试请求和响应内容
🚫 不建议用 curl 大规模抓百度网页:
百度、谷歌、B站、微博等大厂都启用了 复杂的反爬虫机制,用 curl 是"裸奔"方式,很容易被 ban,甚至封 IP。