Java使用HTMLUnit+html2canvas生成图片报Cannot modify readonly property错误
核心问题定位
- HTMLUnit 2.5.2 版本过老,对现代JS语法、原生对象属性操作的兼容性极差,是触发
Cannot modify readonly property: constructor报错的直接原因 - 资源获取逻辑错误:html2canvas生成的图片是前端JS运行时动态生成的,不存在于初始页面的响应流中,直接读取当前窗口页面的响应流得到的是原始HTML内容,存为png自然是损坏空白文件
快速解决方案
按优先级执行以下操作:
- 优先升级HTMLUnit到最新稳定版,老旧版本对html2canvas这类现代前端库的兼容缺陷极多,升级后可以直接解决90%的原生对象属性只读报错
- 若暂时无法升级版本,在加载目标页面前提前注入JS补丁,开放对应原生对象的constructor写入权限:
WebClient webClient = new WebClient(BrowserVersion.CHROME); // 原有配置保留 webClient.getOptions().setCssEnabled(true); webClient.getOptions().setJavaScriptEnabled(true); webClient.getOptions().setThrowExceptionOnScriptError(false); // 新增注入补丁 webClient.executeJavaScript(""" Object.defineProperty(HTMLOptionElement.prototype, 'constructor', { writable: true }); Object.defineProperty(MutationObserver.prototype, 'constructor', { writable: true }); Object.defineProperty(URL.prototype, 'constructor', { writable: true }); """);
- 修正图片获取逻辑,不要直接读取当前页面响应流,等JS运行完成后执行页面JS拿到动态生成的图片base64内容再解码存储:
URL url = new URL(targetUrl); HtmlPage htmlPage = webClient.getPage(url); // 新增视口配置,避免html2canvas渲染空视口导致空白图,尺寸可根据实际渲染需求调整 htmlPage.getEnclosingWindow().setOuterWidth(1920); htmlPage.getEnclosingWindow().setOuterHeight(1080); // 延长等待时间确保渲染完成 webClient.waitForBackgroundJavaScript(10000); // 执行JS获取生成的图片base64,选择器可根据页面实际结构调整 String base64Content = (String) htmlPage.executeJavaScript("return document.querySelector('#生成的canvas或者img元素的选择器').toDataURL('image/png').split(',')[1]").getJavaScriptResult(); // 解码base64写文件 byte[] imgBytes = Base64.getDecoder().decode(base64Content); try (OutputStream os = new FileOutputStream(new File(path + "/generatedPic.png"))) { os.write(imgBytes); }
内容的提问来源于stack exchange,提问作者m3_
相关产品推荐
相关产品推荐

