如何使用Selenium(Java)实现Vaadin Upload文件上传?
Vaadin Upload 组件的 Selenium Java 文件上传方案
Vaadin Upload 不生成传统的 <input type="file"> 元素,直接向 target URL 发 POST 请求失败的核心原因是请求未携带浏览器会话的认证信息(如 Cookie、CSRF Token),服务器会拒绝无会话的上传请求。以下是可行的实现方案:
核心思路
利用 Selenium 的 JavascriptExecutor 在浏览器上下文内发送上传请求,自动复用当前浏览器的会话 Cookie 和 Vaadin 所需的请求头,避免会话不一致问题。
具体代码实现
import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.By; public class VaadinUploadHandler { public static void uploadFile(WebDriver driver, String filePath) { // 定位 Vaadin Upload 组件 WebElement uploadElement = driver.findElement(By.tagName("vaadin-upload")); String targetUrl = uploadElement.getAttribute("target"); // 构造 JavaScript 代码,在浏览器内发送上传请求 String jsScript = String.format(""" return new Promise((resolve, reject) => { const fileInput = document.createElement('input'); fileInput.type = 'file'; fileInput.style.display = 'none'; fileInput.onchange = function() { const file = this.files[0]; const formData = new FormData(); formData.append('file', file); const xhr = new XMLHttpRequest(); xhr.open('POST', '%s', true); xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.responseText); } else { reject(new Error('Upload failed with status: ' + xhr.status)); } }; xhr.onerror = function() { reject(new Error('Network error during upload')); }; xhr.send(formData); }; document.body.appendChild(fileInput); fileInput.dispatchEvent(new MouseEvent('click')); arguments[0].sendKeys('%s'); document.body.removeChild(fileInput); }); """, targetUrl, filePath); try { // 执行 JS 并等待上传完成 ((JavascriptExecutor) driver).executeAsyncScript(jsScript, uploadElement); System.out.println("文件上传成功"); } catch (Exception e) { System.err.println("文件上传失败: " + e.getMessage()); } } }
关键细节说明
- 会话复用:通过浏览器内的
XMLHttpRequest发送请求,自动携带当前会话的 Cookie(如JSESSIONID)和 Vaadin 内部的 CSRF 令牌,避免服务器认证拦截。 - FormData 格式:Vaadin Upload 期望接收
multipart/form-data格式的请求,通过FormData构造符合要求的表单数据。 - 异步执行:使用
executeAsyncScript等待上传请求完成,确保 Selenium 不会提前执行后续操作。
替代方案(针对 Vaadin 14+)
如果上述方法仍有问题,可以尝试直接触发 Vaadin Upload 组件内部的上传逻辑:
WebElement uploadElement = driver.findElement(By.tagName("vaadin-upload")); // 定位组件 Shadow DOM 内的 input 元素 WebElement internalInput = (WebElement) ((JavascriptExecutor) driver).executeScript(""" const upload = arguments[0]; const input = upload.shadowRoot.querySelector('input[type="file"]'); input.style.display = 'block'; return input; """, uploadElement); // 执行传统的文件上传操作 internalInput.sendKeys(filePath);
注:Vaadin 组件使用 Shadow DOM,需通过 shadowRoot 定位内部的 input 元素。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

