使用 http.client 并发检测死链时,须设 timeout 控制请求生命周期,用 waitgroup+channel 限并发,结合状态码、响应体内容及重定向处理综合判断“死链”,并用 golang.org/x/net/html 安全提取链接。

用 http.Client 发起并发请求时,别忘了设置超时
死链检测本质是大量发 HTTP 请求,不设超时的话,一个卡住的链接会让整个 goroutine 永久阻塞,最终耗尽资源。Go 默认的 http.DefaultClient 没有超时,必须显式配置。
- 用
&http.Client{Timeout: 10 * time.Second}控制单次请求上限 - 别只设
net.DialTimeout,它只管建连;要覆盖整个请求生命周期,用Timeout字段 - 如果需要更精细控制(比如分开设置连接、读、写超时),改用
Transport配置,但对死链检测来说,Timeout足够且不易出错
用 sync.WaitGroup + chan 控制并发量,不是无脑开 1000 个 goroutine
爬全站链接时,可能一次性拿到几千 URL。全丢进 goroutine 不仅容易被目标服务器限流或拉黑,还会触发系统文件描述符耗尽、DNS 查询阻塞等问题。
- 固定 worker 数量:启动 10–50 个长期运行的 goroutine,从 channel 里取 URL 处理
- 用
sync.WaitGroup等待所有任务结束,别依赖time.Sleep或计数器手动判断 - channel 缓冲区大小设为待检测 URL 总数,避免发送端阻塞;接收端关闭 channel 后,worker 自动退出
判断“死链”的依据不能只看 status != 200
HTTP 状态码只是第一层信号。404 是典型死链,但 301/302 跳转目标不可达、503 临时不可用、甚至 200 但返回空页或错误 HTML,都该归为异常。
- 必须检查
resp.StatusCode,但也要读取响应体前几十字节,确认是否真返回了有效内容(比如含或预期关键词) - 对重定向,建议设
CheckRedirect为func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse },自己处理跳转逻辑,避免丢失中间状态 - 遇到
net/http: request canceled或context deadline exceeded这类错误,属于超时或主动取消,应单独归类,不和 4xx/5xx 混淆
解析 HTML 提取链接时,优先用 golang.org/x/net/html,别正则匹配
网页中 <a href="..."></a> 的格式千奇百怪:引号可有可无、空格位置随意、URL 可能是相对路径。正则极易漏匹配或误伤。
立即学习“go语言免费学习笔记(深入)”;
-
golang.org/x/net/html是 Go 官方维护的健壮解析器,能正确处理嵌套、命名空间、自闭合标签等边界情况 - 提取
href后,用url.Join(baseURL, href)转成绝对地址,baseURL 是当前页面 URL,不是根域名 - 注意过滤掉
javascript:、mailto:、tel:等非 HTTP 协议链接,避免http.Get报unsupported protocol scheme
真正难的不是并发或发请求,而是怎么定义“死”——是服务器没响应?是返回了 404?还是页面结构崩了但 HTTP 状态码还是 200?这些判断逻辑得贴着业务来,没法靠工具自动猜准。










