我有一个功能,分配任务的请求,使独特的请求,也需要独特的cookie。
func DistributeTasks(url string) error {
// redacted code
responseCh := make(chan utilities.WebsiteData, len(distributedCoupons))
errorCh := make(chan error)
var wg sync.WaitGroup
var cookieJarMutex sync.Mutex
for _, couponArray := range distributedCoupons {
wg.Add(1)
CookieJar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
if err != nil {
cookieJarMutex.Lock()
errorCh <- err
cookieJarMutex.Unlock()
}
go func(couponArray utilities.TaskData) {
defer wg.Done()
cookieJarMutex.Lock() // Acquire the mutex
_, err = TaskToDistribute(parsedURL, couponArray, responseCh, errorCh, CookieJar)
cookieJarMutex.Unlock() // Release the mutex
if err != nil {
cookieJarMutex.Lock()
errorCh <- err
cookieJarMutex.Unlock()
}
}(couponArray)
}
go func() {
wg.Wait()
close(responseCh)
close(errorCh)
}()
// Channels are handled here, also redacted
}
字符串
这很好地分配了任务,但即使在创建了不同的cookie jar之后,cookie也会堆积在每个请求上(基本上是将所有cookie都放在一个jar中),并且只有在执行了几个任务之后,Web服务器才会开始返回cookie过大的错误(确认cookie超过20,000个字符)。在查看它时,每次都会从每个单独的请求中添加会话令牌(所有会话令牌都在同一个jar中)。
下面是生成HTTP请求的代码:
for _, task:= range taskData.tasks{
// Prepare GraphQL to be sent off to test a promo code
GraphQLQuery := CreateGraphQLQuery(taskDataV2, parsedSessionCookie, testProduct_ProductID)
// Test Coupon
CouponValue, err := TestCoupon(*parsedURL, GraphQLQuery, &taskData.ProxyURL, CookieJar)
if err != nil {
log.Error(err)
}
// Redacted return code
// Wait Time Between to avoid ratelimiting
time.Sleep(350 * time.Millisecond)
}
型
测试试样:
func TestCoupon(domain url.URL, GraphQLquery string, proxyURL *url.URL, CookieJar *cookiejar.Jar) (util.PromoCode, error) {
var parsedData util.ShopifyPromoResponse
GRAPHQL_URL := ParsedURLtoString(domain) + "/testData"
// Make the Request
client := &http.Client{
Jar: CookieJar,
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
request, err := http.NewRequest(http.MethodPost, GRAPHQL_URL, strings.NewReader(GraphQLquery))
PrintHeaders(&request.Header)
if err != nil {
log.Error(err)
}
request.Header = util.Headers
response, err := client.Do(request)
if err != nil {
log.Error(err)
}
// Redacted return code
}
型
这是一个非常奇怪的问题,我无法理解!谢谢你,谢谢
我已经尝试过(如上所示)为每个函数调用使用不同的CookieJar,这并不像在函数本身中初始化CookieJar那样有效。这些函数在cookie中具有与调用它们时相同的会话令牌。(函数调用5将拥有函数调用1、2、3和4的所有会话令牌)函数调用引用从分发器调用的goroutine。
1条答案
按热度按时间bzzcjhmw1#
因为
util.Headers
不包含Cookie
头(每个注解)。这应该意味着http.Client
确实在为每个单独的请求使用CookieJar
。您需要调试此问题:在代码中的不同位置打印出
CookieJar
的内容,以确认cookie没有在不同的CookieJars
之间共享。您可以打印出
CookieJar
的内容(名称和值),如下所示:字符串
您可以在
TestCoupon
函数中紧接在client.Do(request)
之前和之后调用此函数。这将让您看到在请求中发送了哪些cookie,以及在请求后收到并存储在CookieJar
中的cookie。检查是否有任何请求的响应cookie设置了
Domain
属性。如果设置了Domain
属性,则cookie对该域的所有子域也有效。注意:您已经使用
sync.Mutex
来处理cookieJarMutex
的错误,这很好,但真实的上没有必要使用互斥锁来保护对错误通道的访问。通道被设计成可以安全地被多个goroutine并发使用,你也可以向errorCh
通道发送错误,而不需要锁定互斥锁:型
另见“When should you use a mutex over a channel?”
但是当打印出
response.Request.Header
(发出的请求)时,提供的cookie头长度超过20,000个字符,这意味着所有的CookirJars
都以某种方式组合在一起。这在几个请求后显示,Web服务器启动错误,因为cookie太大。我可以建议尝试为每个goroutine创建一个全新的客户端。在现有的代码中,您正在跨goroutines共享
http.Client
。为了隔离这一点,尝试在goroutine中创建一个带有自己的cookie jar的新客户端。
型
这种方法为每个goroutine创建了一个唯一的客户端和cookie jar,这可能对您的场景有所帮助。
这意味着
TaskToDistribute
函数需要修改为接受*http.Client
作为参数,而不是*cookiejar.Jar
,并使用该客户端发出HTTP请求。型
TestCoupon
:型
即使在更新它以删除互斥体并创建和使用新的HTTP客户端之后,头仍然以某种方式合并。
看看你的
TestCoupon
函数:型
这一行实际上替换了
request
的整个Header
,这意味着它可能会丢弃之前设置的任何Cookie
头(由http.Client
在执行Do
时设置)。客户端的cookie jar在执行请求之前自动设置jar中的Cookie
头。您可以只更新您感兴趣的特定头文件,而不是替换整个头文件,就像这样:
型
这样,您可以保留
http.Client
从cookie jar设置的Cookie
头,以及Go的HTTP包可能自动设置的任何其他头。