urlconnection是抽象基类,仅定义基础连接行为;http特有功能(如setrequestmethod、getresponsecode、请求头设置、状态码判断、超时控制、gzip解压等)均由httpurlconnection子类实现,不转型则无法可靠发起http请求或正确处理响应。

URLConnection 本身不直接支持 HTTP 方法设置或状态码检查,必须强制转成 HttpURLConnection 才能可靠发起请求、读取 HTML 源码。直接用 URLConnection 调 getInputStream() 很可能抛出 IOException 或返回空内容,尤其遇到重定向、403、gzip 压缩等情况时。
为什么必须转型为 HttpURLConnection
URLConnection 是抽象基类,只定义了基础连接行为;而真实 HTTP 交互(如 setRequestMethod、getResponseCode、setRequestProperty)全在 HttpURLConnection 子类里实现。不转型就等于拿遥控器当砖头使——按不动开关,还怪电视没反应。
- 不转型时调用
setRequestMethod("GET")会报IllegalStateException或静默失效 - 无法判断响应是否成功(
HTTP_OK),容易把 404/500 当作正常内容读取 - 部分网站(如 GitHub、知乎)会根据
User-Agent和Accept头拒绝非浏览器请求,这些头只能通过HttpURLConnection设置
setConnectTimeout 和 setReadTimeout 必须显式设
默认超时是无限等待,网络卡顿、DNS 慢、服务器假死都会让线程 hang 死。这两个参数不是可选项,是保命配置。
-
setConnectTimeout(8000):建立 TCP 连接的最长时间,单位毫秒。低于 3000 容易误判正常网络抖动 -
setReadTimeout(8000):从 socket 读取数据的单次阻塞上限。注意:它不控制整个响应读取耗时,只管每次read()调用 - Android 上建议不超过 10 秒,否则可能触发 ANR;服务端批量采集可放宽到 15–30 秒,但需配合重试逻辑
字符编码必须显式指定,不能依赖系统默认
网页的 Content-Type 响应头常带 charset=utf-8,但 InputStreamReader 不会自动解析它。用 new InputStreamReader(conn.getInputStream()) 相当于用平台默认编码(Windows 是 GBK,Linux/macOS 是 UTF-8),一读中文就乱码。
- 优先从响应头提取编码:
connection.getContentEncoding()可得gzip,但编码得看connection.getContentType()解析charset=后缀 - 更稳妥做法:固定用
StandardCharsets.UTF_8(Java 7+),多数现代网站已默认 UTF-8;若遇 GB2312/GBK 站点(如某些政府旧站),再 fallback 到"GBK" - 示例写法:
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)
别忘了 disconnect() 和 try-with-resources
HttpURLConnection 不会自动释放底层 socket,不手动断开或不进 try 块,会导致连接泄漏,尤其在高频请求或 Android Activity 重建场景下极易引发 SocketException: Too many open files。
- 必须在 finally 块或 try-with-resources 中调用
connection.disconnect() - 输入流也要关:用
try (BufferedReader r = new BufferedReader(...)) { ... }自动 close - 注意:调用
disconnect()后不能再读取流,顺序不能颠倒
最容易被忽略的是响应体压缩(gzip/deflate)——很多网站默认开启,但 HttpURLConnection 不自动解压,你读到的是一堆二进制乱码字节。要处理它,得先检查 connection.getContentEncoding() 是否为 "gzip",再套一层 GZIPInputStream。这点连不少老项目都漏掉,结果爬回来的 HTML 里全是 符号。










