使用Flying Saucer生成PDF时CSS与样式无法渲染问题
解决Flying Saucer生成PDF时不加载CSS样式的问题
问题分析
你当前的代码存在几个关键问题导致CSS无法加载:
- UserAgentCallback设置顺序错误:你在
setDocumentFromString之后才设置UserAgent,此时渲染上下文已初始化,设置不会生效。 - 缺少认证信息传递:
NaiveUserAgent默认不会携带Basic认证头,加载CSS资源时服务器会返回401,无法获取样式文件。 - HtmlCleaner可能修改链接:如果HtmlCleaner的配置不当,可能会篡改CSS的href路径,导致资源定位失败。
解决方案
1. 调整UserAgent设置顺序
必须在调用setDocumentFromString之前设置UserAgentCallback,确保渲染上下文初始化时就能正确识别基础URL。
2. 自定义带认证的UserAgent
继承NaiveUserAgent,重写资源加载方法,添加Authorization头,保证CSS资源请求时携带认证信息:
public class AuthNaiveUserAgent extends NaiveUserAgent { private final String authHeader; public AuthNaiveUserAgent(String baseUrl, String authHeader) { super(baseUrl); this.authHeader = authHeader; } @Override protected InputStream openStream(String url) throws IOException { HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); // 传递认证头 connection.setRequestProperty("Authorization", authHeader); return connection.getInputStream(); } }
3. 优化HtmlCleaner配置(可选)
如果必须使用HtmlCleaner,确保它不会修改CSS链接属性:
CleanerProperties cleanerProperties = cleaner.getProperties(); cleanerProperties.setKeepOriginalAttributes(true); // 保留原属性,不修改href cleanerProperties.setOmitComments(true); cleanerProperties.setPruneEmptyTags(true);
如果原HTML是标准合规的,也可以直接去掉HtmlCleaner步骤,避免不必要的修改。
4. 修改后的完整Java代码
try { String urlcheck = "http://localhost:8888/index.html"; HttpURLConnection connection = (HttpURLConnection) new URL(urlcheck).openConnection(); connection.setRequestMethod("GET"); // 生成认证头 String username = "admin"; String password = "admin"; String authString = username + ":" + password; String encodedAuthString = Base64.getEncoder().encodeToString(authString.getBytes()); String authHeader = "Basic " + encodedAuthString; connection.setRequestProperty("Authorization", authHeader); int responseCode = connection.getResponseCode(); if (responseCode == 200) { InputStream urlInputStream = connection.getInputStream(); LOG.info("PDF START "); ITextRenderer renderer = new ITextRenderer(); String htmlContent = convertInputStreamToString(urlInputStream); // 可选:如果需要清理HTML,配置CleanerProperties /* HtmlCleaner cleaner = new HtmlCleaner(); CleanerProperties cleanerProperties = cleaner.getProperties(); cleanerProperties.setKeepOriginalAttributes(true); TagNode rootTagNode = cleaner.clean(htmlContent); XmlSerializer xmlSerializer = new PrettyXmlSerializer(cleanerProperties); String cleanedHtml = xmlSerializer.getAsString(rootTagNode); */ // 设置带认证的UserAgent(必须在setDocument之前) String baseUrl = "http://localhost:8888"; renderer.getSharedContext().setUserAgentCallback(new AuthNaiveUserAgent(baseUrl, authHeader)); // 使用原HTML或清理后的HTML renderer.setDocumentFromString(htmlContent); // 或者cleanedHtml ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); renderer.layout(); renderer.createPDF(outputStream); renderer.finishPDF(); } else { LOG.error("Failed to retrieve URL content. Response code: " + responseCode); } } catch (Exception e) { LOG.error("PDF generation failed", e); }
额外提示
- 可以直接使用
renderer.setDocumentFromString(htmlContent, baseUrl)简化基础URL的设置,但如果需要认证,仍需自定义UserAgent。 - 检查CSS文件的路径是否正确,确保
/css/xxx.css能通过baseUrl拼接成完整可访问的URL(如http://localhost:8888/css/xxx.css)。
内容的提问来源于stack exchange,提问作者ezhil
相关产品推荐
相关产品推荐

