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

Python socket请求www.google.com返回301但curl返回200的原因

问题核心原因

你遇到的问题根本不是“跳转地址和原请求一致”,是你手写HTTP请求时犯了非常基础的头字段错误:

  • 你的TCP连接确实正确连到了www.google.com的80端口,但HTTP/1.1协议要求请求必须携带Host头,用来告诉服务端当前请求要访问哪个站点(同一个IP可以托管多个域名站点)。
  • 你代码里写的Host头值是google.com,和你实际要访问的www.google.com不是同一个站点。服务端收到请求后,识别到你访问的是不带www的根域,因此返回301状态码,要求跳转到带www的http://www.google.com/地址。你肉眼觉得跳转地址和你请求的地址一样,本质是你忽略了自己写错Host头的事实,产生了认知偏差。

curl/wget 和手写socket代码的行为差异

二者的实现逻辑差异主要在两点:

  1. 请求头自动填充逻辑
    当你用curl/wget请求www.google.com时,工具会自动从你输入的URL中解析出正确的主机名,自动填充匹配的Host: www.google.com请求头,不会出现手写代码时漏写www.前缀的低级笔误。
  2. 跳转处理逻辑
    • wget默认开启3xx跳转自动跟随,收到301/302类状态码时会自动向跳转后的地址发起新请求,直到拿到最终响应。
    • curl默认不自动跟随跳转,需要添加-L参数才会开启该功能。
      你测试时拿到200状态码,核心原因是工具第一次发请求时Host头就是正确的,后续哪怕遇到HTTP转HTTPS的跳转,工具也会按内置逻辑自动处理;而你的裸socket代码只发了一次带错误Host头的请求,收完4096字节响应就直接关闭连接,既没写对核心请求头,也没实现任何跳转处理逻辑,自然拿不到正常的200响应。

修复方式

把你代码里的请求头Host字段值改成和目标主机一致即可:

import socket

target_host = "www.google.com"
target_port = 80

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((target_host, target_port))
# 修正Host头为www.google.com
client.send(b"GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n")
response = client.recv(4096) 
client.close()
print(response)

修正后你会发现返回的301响应会提示跳转到HTTPS地址,而非之前的同名www地址,就能验证之前的301完全是Host头写错导致的。

注:用裸socket手写HTTP请求需要自己处理所有协议细节,包括头字段校验、编码、跳转、长连接、重定向、异常处理等,成熟的HTTP客户端工具已经把这些容易踩坑的细节全部封装实现,正常业务开发不建议直接从socket层手写HTTP请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 04:27:23