Selenium获取下载文件名报错:arguments[0].getResponseHeader不是函数
问题详情
尝试从下载请求的响应头中读取文件名,执行时触发JavaScript异常。
点击下载按钮的代码:
public void clickOnDownloadBtn() { UIPageAction UIPgAct = new UIPageAction(); UIPgAct.clickBtnByButtonLabel("Download Button group with a nested menu"); commonLoginPom.waitForLoadingImageIsNotPresent(); waitForAlertMessage("Download"); }
下载完成后验证文件名的代码(异常触发处已标注):
public void verifyDownloadedFile(String fileType) { String dateAndTime = UIPgAct.getSpecificDate(0,"yyyyMMddHHmm"); String expFileName = "dartts-search-"+dateAndTime; JavascriptExecutor js = (JavascriptExecutor)driver; // 此处抛出异常 String contentDisposition = (String) js.executeScript("return arguments[0].getResponseHeader('Content-Disposition');", driver.findElement(By.tagName("body"))); String filename = ""; if (contentDisposition != null) { String[] parts = contentDisposition.split(";"); for (String part : parts) { if (part.trim().startsWith("filename")) { filename = part.split("=")[1].trim().replaceAll("\"", ""); break; } } logger.info("File name is "+filename); } }
错误信息
org.openqa.selenium.JavascriptException: javascript error:
arguments[0].getResponseHeader is not a function (Session info:
chrome=122.0.6261.69) Build info: version: '4.26.0', revision:
'8ccf0219d7' System info: os.name: 'Windows 11', os.arch: 'amd64',
os.version: '10.0', java.version: '17.0.8' Driver info:
org.openqa.selenium.remote.RemoteWebDriver$ByteBuddy$Juadff3R$ByteBuddy$SBnWYgkD
Command: [3f87c1092c0fe1ddd23a59697666d2bb, executeScript
{args=[{element-6066-11e4-a52e-4f735466cecf=f.C9CDA9F3320EF6FD01EFEB826B056B33.d.DDC4FA9BCE14C3E0BD3747C7CBD788C1.e.190}],
script=return arguments[0].getResponseHeader('Content-Disposition');}]
Capabilities {acceptInsecureCerts: false, browserName: chrome,
browserVersion: 122.0.6261.69, chrome: {chromedriverVersion:
122.0.6261.69 (81bc525b6a36..., userDataDir: /tmp/.org.chromium.Chromium...}, fedcm:accounts: true,
goog:chromeOptions: {debuggerAddress: localhost:9222},
networkConnectionEnabled: false, pageLoadStrategy: normal,
platformName: linux, proxy: Proxy(), se:bidiEnabled: false, se:cdp:
ws://selenium-grid.raven-ek..., se:cdpVersion: 122.0.6261.69, se:vnc:
ws://selenium-grid.raven-ek..., se:vncEnabled: true,
se:vncLocalAddress: ws://100.64.56.255:7900, setWindowRect: true,
strictFileInteractability: false, timeouts: {implicit: 0, pageLoad:
300000, script: 30000}, unhandledPromptBehavior: dismiss and notify,
webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true,
webauthn:extension:minPinLength: true, webauthn:extension:prf: true,
webauthn:virtualAuthenticators: true} Session ID:
3f87c1092c0fe1ddd23a59697666d2bb at
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
Method) at
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at
java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at
java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at
java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.openqa.selenium.remote.ErrorCodec.decode(ErrorCodec.java:167)
at
org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:138)
at
org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:50)
原因
传入executeScript的参数是DOM元素(body标签),而getResponseHeader是XMLHttpRequest对象的专属方法,DOM元素不具备该方法,因此触发"is not a function"异常。
解决方案
方案1:用Selenium CDP监听网络响应(推荐)
Selenium 4+支持通过Chrome DevTools Protocol直接捕获网络请求的响应头,无需依赖JS:
public void verifyDownloadedFile(String fileType) { String dateAndTime = UIPgAct.getSpecificDate(0,"yyyyMMddHHmm"); String expFileName = "dartts-search-"+dateAndTime; // 启用网络监听 ((ChromeDriver) driver).executeCdpCommand("Network.enable", new HashMap<>()); // 添加响应监听逻辑 ((ChromeDriver) driver).addListener(new WebDriverListener() { @Override public void onResponseReceived(WebDriver driver, HttpResponse response) { // 筛选下载相关的响应 if (response.getUri().contains("download") && response.getHeaders().containsKey("Content-Disposition")) { String contentDisposition = response.getHeaders().get("Content-Disposition"); String filename = ""; if (contentDisposition != null) { String[] parts = contentDisposition.split(";"); for (String part : parts) { if (part.trim().startsWith("filename")) { filename = part.split("=")[1].trim().replaceAll("\"", ""); break; } } logger.info("File name is "+filename); // 验证文件名是否符合预期 assert filename.contains(expFileName) : "下载文件名不符合预期:"+filename; } } } }); // 触发下载操作 clickOnDownloadBtn(); // 关闭网络监听 ((ChromeDriver) driver).executeCdpCommand("Network.disable", new HashMap<>()); }
方案2:直接检查下载目录文件
如果不需要从响应头获取,可直接验证浏览器下载目录中的文件:
public void verifyDownloadedFile(String fileType) { String dateAndTime = UIPgAct.getSpecificDate(0,"yyyyMMddHHmm"); String expFileName = "dartts-search-"+dateAndTime; // 浏览器默认下载路径,可根据实际配置修改 String downloadDir = System.getProperty("user.home") + "/Downloads"; File dir = new File(downloadDir); // 筛选包含预期文件名且对应后缀的文件 File[] files = dir.listFiles((f) -> f.getName().contains(expFileName) && f.getName().endsWith(fileType)); assert files != null && files.length > 0 : "未找到预期下载文件:"+expFileName; logger.info("找到下载文件:"+files[0].getName()); }
方案3:修正JS逻辑(不推荐)
若坚持用JS,需创建XMLHttpRequest重新请求下载接口,但可能触发重复下载,且需提前知道下载接口URL:
public void verifyDownloadedFile(String fileType) { String dateAndTime = UIPgAct.getSpecificDate(0,"yyyyMMddHHmm"); String expFileName = "dartts-search-"+dateAndTime; JavascriptExecutor js = (JavascriptExecutor)driver; // 替换为实际的下载接口URL String downloadUrl = "https://your-domain.com/api/download"; String contentDisposition = (String) js.executeScript("var xhr = new XMLHttpRequest();" + "xhr.open('GET', '" + downloadUrl + "', false);" + "xhr.send();" + "return xhr.getResponseHeader('Content-Disposition');"); String filename = ""; if (contentDisposition != null) { String[] parts = contentDisposition.split(";"); for (String part : parts) { if (part.trim().startsWith("filename")) { filename = part.split("=")[1].trim().replaceAll("\"", ""); break; } } logger.info("File name is "+filename); assert filename.contains(expFileName) : "下载文件名不符合预期"; } }
内容的提问来源于stack exchange,提问作者VinnyTech

