You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Playwright-Go多API响应等待遇异常,请求代码排查

Playwright-Go多响应等待问题排查与修复

核心问题分析

你的代码出现日志2仅打印一次、日志4无法执行的情况,核心原因有以下几点:

  • WaitForResponse匹配阻塞:当传入字符串作为匹配条件时,Playwright会精确匹配响应的完整URL。如果实际请求存在重定向、URL编码差异(如参数顺序、特殊字符转义),会导致多数协程的WaitForResponse一直阻塞,无法执行后续代码和wg.Done(),最终wg.Wait()永远等待,日志4无法输出。
  • defer wg.Done()位置错误:当前代码将defer放在函数末尾,若WaitForResponse一直阻塞,defer永远不会执行;即使等待出错触发panic,也无法提前保证WaitGroup计数递减。
  • 未处理等待错误:page.WaitForResponse()返回错误值,忽略错误会导致等待失败时无法感知,协程直接异常退出,进一步导致WaitGroup计数无法正常递减。
  • 固定数组存在越界风险:[5]playwright.Response是固定长度数组,若dashboardIds长度超过5,赋值时会触发panic。

修复后的代码

func waitResponse(dashboardIds []int, page playwright.Page) {
    // 用切片替代固定数组,适配任意长度的dashboardIds
    responses := make([]playwright.Response, len(dashboardIds))
    wg := sync.WaitGroup{}
    baseUrl := "https://example.com"

    for index, v := range dashboardIds {
        wg.Add(1)
        targetUrl := fmt.Sprintf("%s/%d?dashboard_id=114", baseUrl, v)
        currentIdx := index

        // 启动协程时传入局部变量,避免闭包变量捕获问题
        go func(url string, idx int) {
            // 立即defer,确保协程无论正常退出还是异常退出,都能通知WaitGroup
            defer wg.Done()
            log.Printf("start request %s\n", url) // 1

            // 使用函数式匹配,灵活性更高,可根据实际情况调整匹配逻辑
            response, err := page.WaitForResponse(func(res playwright.Response) bool {
                // 示例:精确匹配URL,可替换为strings.Contains(res.URL(), url)实现包含匹配
                return res.URL() == url
            })
            if err != nil {
                log.Printf("wait for response %s failed: %v", url, err)
                return
            }

            log.Printf("goroutine get response from %s, index is %d\n", url, idx) // 2
            resBody, err := response.Body()
            if err != nil {
                log.Printf("read response body for %s failed: %v", url, err)
                return
            }
            responses[idx] = response
        }(targetUrl, currentIdx)

        // 可选:若不需要全局监听响应,建议移除该注册,避免重复回调
        page.On("response", func(res playwright.Response) {
            if res.URL() == targetUrl {
                log.Printf("listen get response from %s", targetUrl) //3
            }
        })
    }

    wg.Wait()
    log.Printf("all url responded") // 4
}

关键优化说明

  1. 灵活的URL匹配:使用函数式替代字符串匹配,可根据实际场景调整(如包含匹配、正则匹配),避免精确匹配的局限性。
  2. 可靠的WaitGroup管理:在协程启动后立即defer wg.Done(),确保无论协程如何终止,都能正确递减计数。
  3. 错误处理:添加WaitForResponse和response.Body()的错误处理,便于排查问题。
  4. 安全的存储结构:用切片替代固定长度数组,避免越界panic。

内容的提问来源于stack exchange,提问作者miracle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 15:30:50