为什么选项“--explicitly-allowed-ports”在使用 chrome 版本 91.x 和 selenium/chromedriver 无头模式时不起作用?

Why is option "--explicitly-allowed-ports" not working when using chrome version 91.x and selenium/chromedriver headless mode?

我们有很多由 Jenkins 作业触发的基于 selenium 的测试自动化。测试自动化使用 chromedriver 和无头模式。前几天Jenkins节点安装chrome更新到Version91.x,测试用例全部切换到error状态
我们了解到 Chrome 现在将多个端口视为不安全端口,例如我们用于被测系统的端口 10080。一项小小的研究表明,有一个名为“--explicitly-allowed-ports=10080”的 Chrome 选项应该可以解决这个问题。 对于我们来说,它似乎在 运行 selenium test cases with a browser window 时有效,但在无头模式下 运行 时无效。这是一个已知的问题?有人对此有解释或解决方法吗?

这里是重现问题的简化测试用例:

    package com.unsafe.ports;

import java.io.File;

import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class UnsafePortsTest {
@Test
public void testUnsafePorts() {
    String url = "http://__SERVER__:10080/__APP__/";
    WebDriver driver = createChromeDriver(true);
    driver.get(url);
    System.out.println("Now at page: " + driver.getTitle());
    System.out.println("Page source: " + driver.getPageSource());
}

protected WebDriver createChromeDriver(final boolean headless) {
    File driverFile = new File("bin", "chromedriver.exe");
    System.setProperty("webdriver.chrome.driver", driverFile.getAbsolutePath());
    File chromeExePath = new File("C:/Program Files (x86)/Google/Chrome/Application/chrome.exe");
    
    ChromeOptions chromeOptions = new ChromeOptions();
    if (chromeExePath.exists()) {
        chromeOptions.setBinary(chromeExePath);
    }
    if (headless) {
        chromeOptions.addArguments("headless");
    }
    chromeOptions.addArguments("start-maximized");
    chromeOptions.addArguments("disable-infobars");
    chromeOptions.addArguments("--disable-extensions");
    chromeOptions.addArguments("--disable-gpu");
    chromeOptions.addArguments("--disable-gpu-sandbox");
    chromeOptions.addArguments("--ignore-certificate-errors");
    chromeOptions.addArguments("--disable-gpu-compositing");
    chromeOptions.addArguments("--no-sandbox-and-elevated");
    chromeOptions.addArguments("--disable-web-security");
    chromeOptions.addArguments("--hide-scrollbars");
    chromeOptions.addArguments("--enable-automation");
    chromeOptions.addArguments("--disable-dev-shm-usage");
    chromeOptions.addArguments("--explicitly-allowed-ports=10080");

    return new ChromeDriver(chromeOptions);
}

}

这是pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>unsafe-ports</artifactId>
<name>unsafe-ports</name>
<description>unsafe-ports</description>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>
<dependencies>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>3.141.59</version>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-chrome-driver</artifactId>
        <version>3.141.59</version>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-support</artifactId>
        <version>3.141.59</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

下面是我们使用的一些更具体的版本:

此致, 塞巴斯蒂安

我希望 Chrome 90 是临时的。所以我在本地实现了上面的示例,但用 Chromium 93 替换了 Chrome 90。使用 headless=false 一切正常 - 使用 headless=是的,它不起作用。 与此同时,我实施了一个类似的测试,但使用 Playwright(在后台也使用 Chromium):headless=true 和 headless=false 都有效,甚至没有提及 --explicitly-allowed-ports.
在没有 --explicitly-allowed-ports 的情况下直接使用 Chromium 会给出错误:ERR_UNSAFE_PORT.

我的结论:Chrome/Chromium 正确处理不安全端口(无头或无头)。所以可能 ChromeDriver 没有给 Chrome.

正确的信息

一个解决方法是安装旧版本的 Chromium 和 Chromedriver(Chromium 不实现自动更新 - 所以你留在选择的版本)。从 2021 年 1 月底开始的页面 https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Win_x64/ provides builds for Chromium and ChromeDriver. I have chosen build https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Win_x64/848870/。版本 90.0.4404.0 (Entwickler-Build)(64 位)。 我更改了引用相应 Chromium 和 Chromedriver: headless=true 和 headless=false 的测试项目。测试要求 pagetitle 和页面内容,结果是:

Now at page: Ralfi
Page source: <html><head><title>Ralfi</title></head><body><h1 id="ralf">Hello World!</h1></body></html>
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.148 sec

仅供参考:testweb是一个小nodejs。

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end('<html><head><title>Ralfi</title></head><body><h1 id="ralf">Hello World!</h1></body></html>');
}).listen(10080);

顺便说一句:我将您的 Chrome 选项减少为仅包含 --explicitly-allowed-ports=10080