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

Java中用BrowserMob+Selenium捕获请求头却得到空HAR文件

HAR文件条目始终为空的排查与修复

问题背景

目标是读取应用门户的请求头,使用BrowserMob Proxy(BMP)搭配Selenium,但生成的HAR文件中条目始终为空。已尝试移除无头参数、为BMP配置单独SSLProxy,问题仍未解决。环境信息:Java 17、browsermob-core 2.1.5、Selenium 4.7.0。

原代码

package com.example;

import io.github.bonigarcia.wdm.WebDriverManager;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.core.har.HarEntry;
import net.lightbody.bmp.proxy.CaptureType;
import org.openqa.selenium.By;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class webDriver {
    private static final Logger logger
            = LoggerFactory.getLogger(webDriver.class);
            //= LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);

    public static void generateUIToken() throws Exception {
        
        WebDriver driver = null;
        BrowserMobProxy proxy = new BrowserMobProxyServer();
        proxy.setTrustAllServers(true);
        proxy.start(0);
        Har har;
        Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);
        String hostIp = "localhost";
        seleniumProxy.setHttpProxy(hostIp + ":" + proxy.getPort());
        seleniumProxy.setSslProxy(hostIp + ":" + proxy.getPort());
        seleniumProxy.setSslProxy("trustAllSSLCertificates");

        WebDriverManager.chromedriver().setup();
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--no-sandbox");
        options.addArguments("--headless");
        options.addArguments("--ignore-certificate-errors");
        options.addArguments("--disable-dev-shm-usage");

        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(CapabilityType.PROXY, seleniumProxy);
        capabilities.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS,true);
        capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS,true);
        options.merge(capabilities);

        try {

            driver = new ChromeDriver(options);


            proxy.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT);

            proxy.setHarCaptureTypes(CaptureType.REQUEST_HEADERS, CaptureType.RESPONSE_HEADERS);
            proxy.enableHarCaptureTypes(CaptureType.REQUEST_HEADERS,CaptureType.RESPONSE_HEADERS);
            proxy.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT);
            proxy.newHar("new.example.com");

            driver.get("https://new.example.com");

            String title = driver.getTitle();
            TimeUnit.SECONDS.sleep(10);
            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));
            wait.until(ExpectedConditions.elementToBeClickable(By.id("userInput")));
            WebElement user_login = driver.findElement(By.id("userInput"));
            user_login.sendKeys("username");
            user_login.submit();
            logger.info(user_login + " - " + title);
            TimeUnit.SECONDS.sleep(10);

            wait.until(ExpectedConditions.elementToBeClickable(By.id("okta-signin-password")));
            WebElement pass_login = driver.findElement(By.id("okta-signin-password"));
            pass_login.sendKeys("password");
            pass_login.submit();
            logger.info(pass_login + " - " + title);

            TimeUnit.SECONDS.sleep(30);

            logger.info("Current" + driver.getCurrentUrl());
            har = proxy.getHar();
            List<HarEntry> entries = har.getLog().getEntries();
            for (HarEntry entry : entries) {
                logger.info("Request URL: " + entry.getRequest().getUrl());
                logger.info("Entry response status: " + entry.getResponse().getStatus());
                logger.info("Entry response text: " + entry.getResponse().getStatusText());

            }
            har.writeTo(new File("test.har"));
            TimeUnit.SECONDS.sleep(10);
            driver.quit();
            proxy.endHar();
            proxy.stop();

        }
        catch (Exception e){
            assert driver != null;
            driver.close();
            driver.quit();
        }
    }

    public static void main(String[] args) throws Exception {

        generateUIToken();


    }
}

输出的HAR文件

{"log":{"version":"1.2","creator":{"name":"BrowserMob Proxy","version":"2.1.5","comment":""},"pages":[{"id":"new.example.com","startedDateTime":"2022-12-06T21:46:04.043Z","title":"new.example.com","pageTimings":{"comment":""},"comment":""}],"entries":[],"comment":""}}

问题原因与修复方案

1. SSL代理配置错误

代码中seleniumProxy.setSslProxy("trustAllSSLCertificates");这行完全错误,会覆盖之前正确设置的seleniumProxy.setSslProxy(hostIp + ":" + proxy.getPort());,导致浏览器无法通过BMP代理发送HTTPS请求,自然没有捕获到任何条目。直接删除这行代码即可。

2. HAR初始化时机错误

当前代码是先启动WebDriver,再配置HAR捕获规则并创建newHar,这会导致浏览器启动后到HAR初始化前的所有请求都不会被记录。正确顺序应该是:启动BMP代理 → 配置捕获类型 → 创建newHar → 启动WebDriver。

3. 重复配置捕获类型

代码中多次重复调用enableHarCaptureTypes和setHarCaptureTypes,冗余且可能导致配置冲突,只需要一次调用即可涵盖所有需要捕获的类型。

4. 无头模式优化(可选)

无头模式下可添加--disable-gpu参数,并确保代理配置正确传递,同时BMP已设置proxy.setTrustAllServers(true),配合Chrome的--ignore-certificate-errors可解决证书信任问题。

修复后的代码示例

package com.example;

import io.github.bonigarcia.wdm.WebDriverManager;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.core.har.HarEntry;
import net.lightbody.bmp.proxy.CaptureType;
import org.openqa.selenium.By;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class webDriver {
    private static final Logger logger = LoggerFactory.getLogger(webDriver.class);

    public static void generateUIToken() throws Exception {
        WebDriver driver = null;
        BrowserMobProxy proxy = new BrowserMobProxyServer();
        proxy.setTrustAllServers(true);
        proxy.start(0);

        // 1. 先配置HAR捕获类型
        proxy.enableHarCaptureTypes(
                CaptureType.REQUEST_HEADERS,
                CaptureType.RESPONSE_HEADERS,
                CaptureType.REQUEST_CONTENT,
                CaptureType.RESPONSE_CONTENT
        );
        // 2. 创建HAR实例,准备捕获请求
        proxy.newHar("new.example.com");

        // 配置Selenium代理
        Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);
        String hostIp = "localhost";
        seleniumProxy.setHttpProxy(hostIp + ":" + proxy.getPort());
        seleniumProxy.setSslProxy(hostIp + ":" + proxy.getPort());
        // 移除错误的setSslProxy("trustAllSSLCertificates")

        WebDriverManager.chromedriver().setup();
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--no-sandbox");
        options.addArguments("--headless");
        options.addArguments("--disable-gpu"); // 新增无头模式优化参数
        options.addArguments("--ignore-certificate-errors");
        options.addArguments("--disable-dev-shm-usage");

        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(CapabilityType.PROXY, seleniumProxy);
        capabilities.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true);
        capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
        options.merge(capabilities);

        try {
            // 3. 最后启动WebDriver
            driver = new ChromeDriver(options);

            driver.get("https://new.example.com");

            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));
            wait.until(ExpectedConditions.elementToBeClickable(By.id("userInput")));
            WebElement user_login = driver.findElement(By.id("userInput"));
            user_login.sendKeys("username");
            user_login.submit();
            logger.info(user_login + " - " + driver.getTitle());
            TimeUnit.SECONDS.sleep(10);

            wait.until(ExpectedConditions.elementToBeClickable(By.id("okta-signin-password")));
            WebElement pass_login = driver.findElement(By.id("okta-signin-password"));
            pass_login.sendKeys("password");
            pass_login.submit();
            logger.info(pass_login + " - " + driver.getTitle());

            TimeUnit.SECONDS.sleep(30);

            logger.info("Current URL: " + driver.getCurrentUrl());
            Har har = proxy.getHar();
            List<HarEntry> entries = har.getLog().getEntries();
            for (HarEntry entry : entries) {
                logger.info("Request URL: " + entry.getRequest().getUrl());
                logger.info("Entry response status: " + entry.getResponse().getStatus());
                logger.info("Entry response text: " + entry.getResponse().getStatusText());
            }
            har.writeTo(new File("test.har"));

            driver.quit();
            proxy.endHar();
            proxy.stop();

        } catch (Exception e) {
            e.printStackTrace();
            if (driver != null) {
                driver.quit();
            }
            proxy.stop();
        }
    }

    public static void main(String[] args) throws Exception {
        generateUIToken();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 04:15:42