Files
2026-10-11 12:56:38 +08:00

84 lines
2.1 KiB
Go

// 429 详情探针:打印 429 响应的全部头部 + 响应体,看清 CDN 到底怎么限的。
//
// go run ./tools/probe429 -v <图片URL>
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "用法: go run ./tools/probe429 [-v] <图片URL>")
os.Exit(1)
}
url := os.Args[len(os.Args)-1]
verbose := false
for _, a := range os.Args {
if a == "-v" {
verbose = true
}
}
// 先探一张,看当前状态
for round := 1; round <= 3; round++ {
status, hdr, body, err := fullProbe(url, verbose)
if err != nil {
fmt.Printf("[第%d轮] 错误: %v\n", round, err)
continue
}
fmt.Printf("[第%d轮] HTTP %d\n", round, status)
if verbose || status == 429 {
for _, k := range []string{
"Retry-After", "X-RateLimit-Limit", "X-RateLimit-Remaining",
"X-RateLimit-Reset", "X-Cache", "CF-RateLimited",
"Server", "Content-Type", "X-Jetpack-Cache",
} {
if v := hdr.Get(k); v != "" {
fmt.Printf(" %s: %s\n", k, v)
}
}
if s := strings.TrimSpace(body); s != "" {
fmt.Printf(" body: %.300s\n", s)
}
}
if status == 200 {
fmt.Println(" ✓ 这次成功了")
break
}
if round < 3 {
time.Sleep(3 * time.Second)
}
}
}
func fullProbe(url string, verbose bool) (int, http.Header, string, error) {
tr := &http.Transport{ForceAttemptHTTP2: true}
defer tr.CloseIdleConnections()
client := &http.Client{Transport: tr, Timeout: 25 * time.Second}
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return 0, nil, "", err
}
// 用我们客户端的头
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
req.Header.Set("Accept", "image/webp,image/*,*/*;q=0.8")
req.Header.Set("Referer", "https://migmg.ssuu.uk/")
resp, err := client.Do(req)
if err != nil {
return 0, nil, "", err
}
defer resp.Body.Close()
b, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
fmt.Printf(" Proto=%s (2=HTTP/2, 1.1=HTTP/1.1)\n", resp.Proto)
return resp.StatusCode, resp.Header, string(b), nil
}