在官方文档中有提到 `net/http` 是协程安全的,应该复用。
> The Client's Transport typically has internal state (cached TCP connections), so Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
但使用 `Client` 发起请求时,有一部分请求的设置是以函数或字段的方式放在 `Client` 的参数中的。例如 Proxy 代理、重定向检查、超时设置。要设置的话必须像以下这般设置:
```go
func RedirectFunc(req *http.Request, via []*http.Request) error {
if len(via) > 5 {
err := &RedirectError{r}
return WrapErr(err, "RedirectError")
}
return nil
}
client.CheckRedirect = RedirectFunc // 设置重定向
```
这样的话就会造成一个问题,在并发的过程中如果要更改重定向次数的话,就会有并发安全问题,设置 Proxy 代理和超时时间也有这个问题。
比如在这样一个假设情况中,我现在有 10000 个请求需要并发,每个请求需要设置不同的特定 Proxy 代理。那么这时候使用全局的 Client,在每个协程中更改 `client.CheckRedirect` 函数,然后发起请求,显然会有并发问题,发起请求时使用的并不一定是指定的那个 Proxy。
想了想解决的办法:
1. 每个请求新建一个 Client?
2. 把更改参数和请求一起加锁锁起来?
请问这种情况有靠谱的解决方法吗?
这两天已经用 context.Context 实现了这个需求,可以给单个请求指定 Proxy 代理、重定向次数、超时时间了,有兴趣的话可以看一下。
https://github.com/wnanbei/direwolf/blob/master/session.go#L264
https://github.com/wnanbei/direwolf/blob/master/download.go#L18
#8
更多评论
因为重定向次数写死在这个函数里了,要改只能改这个函数。
这个问题的起因主要就以下几点:
1. 因为 Golang net/http 发起请求的时候,是没有办法为单个 Request 请求设置重定向、代理、超时这些设置的,要设置只能设置到 Client 上。
2. Client 底层有连接池,所以需要复用,创建多个新的 Client 来使用开销会很大。
3. 目前需要在并发的情况下更改单个 Request 请求的重定向、代理、超时等设置,但因为 1 的原因只能改 Client。
4. 但复用 Client 的话,Client 的值就类似一个全局变量,在这个协程中更改了,会影响另一个协程中的请求。
情况大致是这么个情况,目前想问的就是有没有更好的解决办法。
#2