org.apache.fop.apps.FOPException:Azure 中的 .fop(访问被拒绝)
org.apache.fop.apps.FOPException: .fop (Access is denied) in Azure
我最近在现有应用程序中添加了一个 fop pdf 生成器。在本地一切正常,但是当我部署到 Azure 上时,出现以下错误:
org.apache.fop.apps.FOPException: .fop (Access is denied)
java.io.FileNotFoundException: .fop (Access is denied)
我很困惑为什么当 fopfactory 写入 ByteOutputstream 时出现异常时我会收到文件访问错误
发生catch的函数是
public static void GeneratePDF(string foFile, HttpContext context) {
StringBuilder sbDebug = new StringBuilder();
sbDebug.AppendLine("Start");
ByteArrayOutputStream os = new java.io.ByteArrayOutputStream();
try
{
sbDebug.AppendLine("Got to 1");
com.sun.org.apache.xerces.@internal.jaxp.SAXParserFactoryImpl s = new com.sun.org.apache.xerces.@internal.jaxp.SAXParserFactoryImpl();
sbDebug.AppendLine("Got to 2");
FopFactory fopFactory = FopFactory.newInstance(new java.io.File(System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/Test.xconf")));
sbDebug.AppendLine("Got to 3 - file ").AppendLine(System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/Test.xconf"));
Fop fop = fopFactory.newFop("application/pdf", os);
sbDebug.AppendLine("Got to 4");
javax.xml.transform.TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance();
javax.xml.transform.Transformer transformer = factory.newTransformer();
javax.xml.transform.Source src = new javax.xml.transform.stream.StreamSource(new java.io.StringReader(foFile));
javax.xml.transform.Result res = new javax.xml.transform.sax.SAXResult(fop.getDefaultHandler());
sbDebug.AppendLine("Got to 5");
transformer.transform(src, res);
context.Response.ContentType = "application/pdf";
context.Response.BinaryWrite(os.toByteArray());
//context.Response.BinaryWrite(System.Text.Encoding.UTF8.GetBytes(os.ToString()));
}
catch (Exception ex) {
throw new Exception(sbDebug.AppendLine(ex.ToString()).ToString());
}
finally {
os.close();
}
}
您可以看到我添加了一些调试行,因为我不得不求助于老式调试来查看发生了什么。
这个输出是:
Catch Error: System.Exception: Start
Got to 1
Got to 2
Got to 3 - file
D:\home\site\wwwroot\App_Data\Test.xconf
org.apache.fop.apps.FOPException: .fop (Access is denied)
java.io.FileNotFoundException: .fop (Access is denied)
所以我可以看到异常发生在这一行:
Fop fop = fopFactory.newFop("application/pdf", os);
除了读取 xconf 文件之外,我希望所有事情都发生在内存中。
2017 年 2 月 21 日更新 我现在已经使用
验证了 xconf 文件存在于正确的位置
string curFile = System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/Test.xconf");
if (System.IO.File.Exists(curFile)) //Used System.IO prefix as without it compiler complains of ambiguity with java.io
{
sbDebug.AppendLine("Got to 3a - file found");
}
else
{
sbDebug.AppendLine("Got to 3a - file NOT found");
}
而且可以使用
阅读
BufferedReader br = new BufferedReader(new FileReader(curFile));
sbDebug.AppendLine("Got to 3b");
String sJIObrOut = br.readLine();
sbDebug.AppendLine("Got to 3c");
while ((sJIObrOut = br.readLine()) != null)
{
sbDebug.Append("3d: ").AppendLine(sJIObrOut);
}
这表明 fopfactory 正在尝试访问其他文件,但我不知道是什么。
感谢收到的任何帮助。
更新 2 22/3/17
我在 Azure 云服务上没有成功,因此决定构建一个本地 Web 应用程序来将 xslfo 文档转换为 pdf 并将其 运行 作为 Web 服务。这在本地完美运行,因此在我们用于其他客户端的服务器上发布了服务。
这不起作用,我得到的错误与我原来的 post 完全相同。这意味着这不是 Azure 的问题 - 有人有任何其他想法吗?
我研究了Apache FOP,我发现PDF生成功能是基于Java AWT which using Default DirectDraw/GDI Pipeline on Windows OS. However, according to the kudu wiki page Azure Web App sandbox,你可以通过搜索关键字GDI
获得GDI的限制信息。所以通常解决方法是使用没有 GDI 的库,但似乎几乎所有 Java 图像库都依赖于 AWT。
除了使用 Azure 云服务或 VM,您无法在包含 WebApps 的 Azure 应用服务上生成 PDF。
非常感谢@mondjunge 为我指明了正确的方向。我现在有一个在 Azure 之外工作的解决方案 - 在适当的时候我希望这将是我可以直接应用于 Azure 的东西,我将相应地添加到这个 post
似乎缓存写入是导致问题的原因(权限)。
我实现的workaround/fix是在xconf文件中加入下面这行(我把它放在/fop结束标签之前,但认为它不重要,只要它是一个直接的子节点fop)
<use-cache>false</use-cache>
希望这可以为其他人省去几天的麻烦和压力
2017 年 7 月 4 日更新
出于兴趣,我尝试将此行添加到纯 azure 托管版本,它不再给我权限错误,而是给了我一个关于 GDI 的错误,这可能与@PeterPan 最初建议的一致。由于我有一个在别处托管的 fop 应用程序的工作版本,我将保留它。
ApacheFOP 将首先在本地创建 .Fop(文件夹) 运行 并在此文件夹内创建缓存-fonts.cache 文件(此缓存文件用于提高性能,如果您想定义一些其他字体,Apache FOP 和许多其他东西不支持)。
如果你进入你的 windows 用户,你会发现这个 .fop 文件夹
无论如何,我认为 azure 不允许 apache fop 在服务器上创建这个 .fop 文件夹以在这个 .fop 中创建 fop-cache.cache 文件
我花了一些时间才得到解决方案!
这是我的问题的解决方案(它正在 windows 服务器上工作)
脚步:
1- 您定义 fop-fonts.cache 所在的路径
2-您必须调整缓存文件的路径
3- 设置缓存路径,fop-fonts.cache 将被创建
代码:
// create just Fop folder and inside this a Cache FOP Folder on your
// project
// Tipp: you could read it from config
// fop-fonts.cache have to be created automaticly, if it is running good
string fopcacheFilePath = "~/Fop/Cache Fop/fop-fonts.cache";
fopcacheFilePath = fopcacheFilePath.Replace("\","/");
fopcacheFilePath = "file:///" + fopcacheFilePath;
fopcacheFilePath = fopcacheFilePath.Replace(" ", "%20");
//in your case you have to set fopcacheFilePath
fopFactory.getFontManager().setCacheFile(new URI(fopcacheFilePath))
如果这段代码 运行 没有问题,那么你必须在你的项目文件夹中找到 fop-fonts.cache
我解决了授予 IIS 用户修改路径的权限:(Windows 服务器)
C:\Windows\system32\config\systemprofile
我本地机器的home路径是User\My User
,但在服务器中是system32文件夹中的路径。
string home = java.lang.System.getProperty("user.home"); // return the home path
希望对你有所帮助。
成功了!
仅供参考
对于典型的 Java Spring Tomcat 应用程序,配置文件应位于 WEB-INF
下
或
从您设置输入流以与配置对象一起使用的源中找到它
--供您参考的示例代码
Resource config = m_appContext.getResource ("/WEB-INF/user_config.xml");
DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder (true);
m_config = builder.build (config.getInputStream ());
FopFactory fopFactory = FopFactory.newInstance();
if (null != m_config)
fopFactory.setUserConfig (m_config);
我最近在现有应用程序中添加了一个 fop pdf 生成器。在本地一切正常,但是当我部署到 Azure 上时,出现以下错误:
org.apache.fop.apps.FOPException: .fop (Access is denied)
java.io.FileNotFoundException: .fop (Access is denied)
我很困惑为什么当 fopfactory 写入 ByteOutputstream 时出现异常时我会收到文件访问错误
发生catch的函数是
public static void GeneratePDF(string foFile, HttpContext context) {
StringBuilder sbDebug = new StringBuilder();
sbDebug.AppendLine("Start");
ByteArrayOutputStream os = new java.io.ByteArrayOutputStream();
try
{
sbDebug.AppendLine("Got to 1");
com.sun.org.apache.xerces.@internal.jaxp.SAXParserFactoryImpl s = new com.sun.org.apache.xerces.@internal.jaxp.SAXParserFactoryImpl();
sbDebug.AppendLine("Got to 2");
FopFactory fopFactory = FopFactory.newInstance(new java.io.File(System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/Test.xconf")));
sbDebug.AppendLine("Got to 3 - file ").AppendLine(System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/Test.xconf"));
Fop fop = fopFactory.newFop("application/pdf", os);
sbDebug.AppendLine("Got to 4");
javax.xml.transform.TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance();
javax.xml.transform.Transformer transformer = factory.newTransformer();
javax.xml.transform.Source src = new javax.xml.transform.stream.StreamSource(new java.io.StringReader(foFile));
javax.xml.transform.Result res = new javax.xml.transform.sax.SAXResult(fop.getDefaultHandler());
sbDebug.AppendLine("Got to 5");
transformer.transform(src, res);
context.Response.ContentType = "application/pdf";
context.Response.BinaryWrite(os.toByteArray());
//context.Response.BinaryWrite(System.Text.Encoding.UTF8.GetBytes(os.ToString()));
}
catch (Exception ex) {
throw new Exception(sbDebug.AppendLine(ex.ToString()).ToString());
}
finally {
os.close();
}
}
您可以看到我添加了一些调试行,因为我不得不求助于老式调试来查看发生了什么。 这个输出是:
Catch Error: System.Exception: Start
Got to 1
Got to 2
Got to 3 - file
D:\home\site\wwwroot\App_Data\Test.xconf
org.apache.fop.apps.FOPException: .fop (Access is denied)
java.io.FileNotFoundException: .fop (Access is denied)
所以我可以看到异常发生在这一行:
Fop fop = fopFactory.newFop("application/pdf", os);
除了读取 xconf 文件之外,我希望所有事情都发生在内存中。
2017 年 2 月 21 日更新 我现在已经使用
验证了 xconf 文件存在于正确的位置string curFile = System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/Test.xconf");
if (System.IO.File.Exists(curFile)) //Used System.IO prefix as without it compiler complains of ambiguity with java.io
{
sbDebug.AppendLine("Got to 3a - file found");
}
else
{
sbDebug.AppendLine("Got to 3a - file NOT found");
}
而且可以使用
阅读BufferedReader br = new BufferedReader(new FileReader(curFile));
sbDebug.AppendLine("Got to 3b");
String sJIObrOut = br.readLine();
sbDebug.AppendLine("Got to 3c");
while ((sJIObrOut = br.readLine()) != null)
{
sbDebug.Append("3d: ").AppendLine(sJIObrOut);
}
这表明 fopfactory 正在尝试访问其他文件,但我不知道是什么。
感谢收到的任何帮助。
更新 2 22/3/17 我在 Azure 云服务上没有成功,因此决定构建一个本地 Web 应用程序来将 xslfo 文档转换为 pdf 并将其 运行 作为 Web 服务。这在本地完美运行,因此在我们用于其他客户端的服务器上发布了服务。 这不起作用,我得到的错误与我原来的 post 完全相同。这意味着这不是 Azure 的问题 - 有人有任何其他想法吗?
我研究了Apache FOP,我发现PDF生成功能是基于Java AWT which using Default DirectDraw/GDI Pipeline on Windows OS. However, according to the kudu wiki page Azure Web App sandbox,你可以通过搜索关键字GDI
获得GDI的限制信息。所以通常解决方法是使用没有 GDI 的库,但似乎几乎所有 Java 图像库都依赖于 AWT。
除了使用 Azure 云服务或 VM,您无法在包含 WebApps 的 Azure 应用服务上生成 PDF。
非常感谢@mondjunge 为我指明了正确的方向。我现在有一个在 Azure 之外工作的解决方案 - 在适当的时候我希望这将是我可以直接应用于 Azure 的东西,我将相应地添加到这个 post
似乎缓存写入是导致问题的原因(权限)。
我实现的workaround/fix是在xconf文件中加入下面这行(我把它放在/fop结束标签之前,但认为它不重要,只要它是一个直接的子节点fop)
<use-cache>false</use-cache>
希望这可以为其他人省去几天的麻烦和压力
2017 年 7 月 4 日更新
出于兴趣,我尝试将此行添加到纯 azure 托管版本,它不再给我权限错误,而是给了我一个关于 GDI 的错误,这可能与@PeterPan 最初建议的一致。由于我有一个在别处托管的 fop 应用程序的工作版本,我将保留它。
ApacheFOP 将首先在本地创建 .Fop(文件夹) 运行 并在此文件夹内创建缓存-fonts.cache 文件(此缓存文件用于提高性能,如果您想定义一些其他字体,Apache FOP 和许多其他东西不支持)。 如果你进入你的 windows 用户,你会发现这个 .fop 文件夹 无论如何,我认为 azure 不允许 apache fop 在服务器上创建这个 .fop 文件夹以在这个 .fop 中创建 fop-cache.cache 文件
我花了一些时间才得到解决方案! 这是我的问题的解决方案(它正在 windows 服务器上工作) 脚步: 1- 您定义 fop-fonts.cache 所在的路径 2-您必须调整缓存文件的路径 3- 设置缓存路径,fop-fonts.cache 将被创建
代码:
// create just Fop folder and inside this a Cache FOP Folder on your
// project
// Tipp: you could read it from config
// fop-fonts.cache have to be created automaticly, if it is running good
string fopcacheFilePath = "~/Fop/Cache Fop/fop-fonts.cache";
fopcacheFilePath = fopcacheFilePath.Replace("\","/");
fopcacheFilePath = "file:///" + fopcacheFilePath;
fopcacheFilePath = fopcacheFilePath.Replace(" ", "%20");
//in your case you have to set fopcacheFilePath
fopFactory.getFontManager().setCacheFile(new URI(fopcacheFilePath))
如果这段代码 运行 没有问题,那么你必须在你的项目文件夹中找到 fop-fonts.cache
我解决了授予 IIS 用户修改路径的权限:(Windows 服务器)
C:\Windows\system32\config\systemprofile
我本地机器的home路径是User\My User
,但在服务器中是system32文件夹中的路径。
string home = java.lang.System.getProperty("user.home"); // return the home path
希望对你有所帮助。
成功了!
仅供参考 对于典型的 Java Spring Tomcat 应用程序,配置文件应位于 WEB-INF
下或
从您设置输入流以与配置对象一起使用的源中找到它
--供您参考的示例代码
Resource config = m_appContext.getResource ("/WEB-INF/user_config.xml");
DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder (true);
m_config = builder.build (config.getInputStream ());
FopFactory fopFactory = FopFactory.newInstance();
if (null != m_config)
fopFactory.setUserConfig (m_config);