You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 21:25:02