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

FOP 2.1中fo:external-graphic无法加载本地服务器图片求助

解决FOP 2.1加载本地服务器图片URL空白的问题

根据你描述的情况,公网图片能正常渲染但本地服务器的图片URL在PDF里显示空白,结合日志里的Image not found报错,核心问题大概率是FOP请求本地接口时缺少必要的身份凭据,或者对本地HTTPS配置不兼容——毕竟公网图片是匿名可访问的,但你的/api/download/image/接口显然需要身份验证,而FOP默认的HTTP请求不会自动携带会话信息(比如Cookie、Token)。下面是几个针对性的解决方案:

1. 给FOP配置自定义HTTP请求处理器,携带身份凭据

FOP默认的资源加载器不会带上你的应用会话信息,所以需要自定义ResourceResolver,让它在请求本地服务器时添加认证头:

实现自定义资源解析器

import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.xmlgraphics.io.Resource;
import org.apache.xmlgraphics.io.ResourceResolver;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;

public class AuthenticatedResourceResolver implements ResourceResolver {
    private final ResourceResolver defaultResolver;
    private final String sessionCookie; // 或者你的认证Token

    public AuthenticatedResourceResolver(ResourceResolver defaultResolver, String sessionCookie) {
        this.defaultResolver = defaultResolver;
        this.sessionCookie = sessionCookie;
    }

    @Override
    public Resource getResource(URI uri) throws IOException {
        // 只针对本地服务器URL做特殊处理
        if ("https".equals(uri.getScheme()) && uri.getHost().equals("localhost")) {
            HttpURLConnection conn = (HttpURLConnection) uri.toURL().openConnection();
            // 添加上你的会话Cookie,或者替换成Authorization Token
            conn.setRequestProperty("Cookie", "JSESSIONID=" + sessionCookie);
            conn.connect();
            return new Resource(conn.getInputStream(), conn.getContentType());
        }
        // 其他URL用默认处理器
        return defaultResolver.getResource(uri);
    }

    @Override
    public void putResource(URI uri, InputStream is) throws IOException {
        defaultResolver.putResource(uri, is);
    }
}

在FOP初始化时配置该解析器

// 原有的FopFactory初始化代码
FopFactory fopFactory = FopFactory.newInstance(new java.net.URI("."), inStr);
// 获取默认资源解析器,替换为自定义的
ResourceResolver defaultResolver = ResourceResolverFactory.createDefaultResourceResolver();
// 传入你的会话ID或认证Token
String yourSessionId = "your-active-session-id";
fopFactory.setResourceResolver(new AuthenticatedResourceResolver(defaultResolver, yourSessionId));
// 后续的PDF生成逻辑保持不变

2. 兼容本地自签名HTTPS证书

如果你的本地服务器用的是自签名SSL证书,FOP的默认HTTP客户端会拒绝信任它,导致请求失败。可以临时添加证书信任(生产环境建议使用正规CA签发的证书):

在自定义ResourceResolver的HTTP请求代码前,添加以下SSL信任配置:

// 跳过SSL证书验证(仅测试环境使用)
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
    }
};

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

// 跳过主机名验证
HostnameVerifier allHostsValid = (hostname, session) -> true;
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

3. 提前下载图片到内存,用Base64嵌入FO模板

如果HTTP请求配置太繁琐,可以先通过你的应用代码获取图片字节数组,转成Base64后直接嵌入FO模板,避免FOP发起外部请求:

步骤1:在生成XML时获取图片Base64

// 调用你的接口获取图片字节数组
byte[] imageBytes = getFileAsResponseEntity(true, 1329, 1304).getBody();
// 转成Base64字符串
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
// 将base64Image存入XML的对应字段,比如<imageBase64>{base64Image}</imageBase64>

步骤2:修改XSL FO模板的图片引用

<xsl:choose>
    <xsl:when test="imageBase64 != ''">
        <!-- 用Base64嵌入图片 -->
        <fo:external-graphic src="data:image/jpeg;base64,{imageBase64}" content-width="scale-down-to-fit" width="100%"/>
    </xsl:when>
    <xsl:otherwise>
        <!--  fallback到外部URL -->
        <fo:external-graphic src="{$ImagePath}" content-width="scale-down-to-fit" width="100%"/>
    </xsl:otherwise>
</xsl:choose>

4. 验证本地接口的响应完整性

先用curl或Postman测试本地接口,确保返回的图片数据完整可打开:

curl -v "https://localhost:4200/api/download/image/?fixedPrice=true&productId=1329&fileId=1304" --output test.jpg

如果test.jpg能正常打开,说明接口返回没问题,问题还是出在FOP的请求配置上。


内容的提问来源于stack exchange,提问作者Marko Taht

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:48:46