Failed to load PDF in chrome/Firefox/IE
笔者的公司搭建了一个Nexus服务器,用来管理我们自己的项目Release构件和Site文档.
今天的问题是当用户访问一个Site里的PDF文件的时候,报错说“detected that the network has been closed.”
但是用右键点击,然后另存为,却每次都能成功下载下来.本来这几天公司的网络确实是不稳定,刚开始还真的以为是网络问题.
后来仔细观察了http请求后发现,每次报错后浏览器都还在不停的发送 http range 请求. 我们用的是Adbobe的PDF插件.
- Chrome问题
Chrome里有一个自带的plugin,可以通过 chrome://plugins 进入plugin配置页面,找到自带的Chrome PDF viewer.
这个Chrome插件发现提供PDF的Nexus服务器支持range请求后,在读取完response的header后会主动abort response.
然后改为通过XHR分批发送Http Range 请求,此时Adbobe的PDF插件就报network已经关闭了。这里的主要原因是两个插件互相冲突,
而且chrome自带的PDF viewer有bug,不能正确组装返回的range response. 解决办法可以是禁用Chrome PDF viewer。
- Firefox问题/IE问题
老版本的IE和Firefox都没问题,有问题的是IE10,Firefox25. 原因是老版本的IE/Firefox里的adobe插件不会发生http range 请求.
新版的IE/Firefox发生了range请求后,服务器也正常的给了response,结果可笑的是adobe 插件不能正确组装,悲剧。
最后想到的就是禁用range请求.但是在流浪器上是做不到的,因为是插件自己发送的.而Nexus服务器2.7.1是hard code支持这个特性的。
range request是http1.1标准里的特性,支持是理所应当的。 下面是NexusContextServlet.Java的部分代码.红色部分显示了这个特性。
protected void doGetFile(final HttpServletRequest request, final HttpServletResponse response,
final StorageFileItem file) throws IOException
{
// ETag, in "shaved" form of {SHA1{e5c244520e897865709c730433f8b0c44ef271f1}} (without quotes)
// or null if file does not have SHA1 (like Virtual) or generated items (as their SHA1 would correspond to template,
// not to actual generated content).
final String etag;
if (!file.isContentGenerated() && !file.isVirtual()
&& file.getRepositoryItemAttributes().containsKey(StorageFileItem.DIGEST_SHA1_KEY)) {
etag = "{SHA1{" + file.getRepositoryItemAttributes().get(StorageFileItem.DIGEST_SHA1_KEY) + "}}";
// tag header ETag: "{SHA1{e5c244520e897865709c730433f8b0c44ef271f1}}", quotes are must by RFC
response.setHeader("ETag", "\"" + etag + "\"");
}
else {
etag = null;
}
// content-type
response.setHeader("Content-Type", file.getMimeType()); // last-modified
response.setDateHeader("Last-Modified", file.getModified()); // content-length, if known
if (file.getLength() != ContentLocator.UNKNOWN_LENGTH) {
// Note: response.setContentLength Servlet API method uses ints (max 2GB file)!
// TODO: apparently, some Servlet containers follow serlvet API and assume
// contents can have 2GB max, so even this workaround below in inherently unsafe.
// Jetty is checked, and supports this (uses long internally), but unsure for other containers
response.setHeader("Content-Length", String.valueOf(file.getLength()));
} // handle conditional GETs only for "static" content, actual content stored, not generated
if (!file.isContentGenerated() && file.getResourceStoreRequest().getIfModifiedSince() != 0
&& file.getModified() <= file.getResourceStoreRequest().getIfModifiedSince()) {
// this is a conditional GET using time-stamp
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
else if (!file.isContentGenerated() && file.getResourceStoreRequest().getIfNoneMatch() != null && etag != null
&& file.getResourceStoreRequest().getIfNoneMatch().equals(etag)) {
// this is a conditional GET using ETag
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
else {
// NEXUS-5023 disable IE for sniffing into response content
response.setHeader("X-Content-Type-Options", "nosniff"); final List<Range<Long>> ranges = getRequestedRanges(request, file.getLength()); // pour the content, but only if needed (this method will be called even for HEAD reqs, but with content tossed
// away), so be conservative as getting input stream involves locking etc, is expensive
final boolean contentNeeded = "GET".equalsIgnoreCase(request.getMethod());
if (ranges.isEmpty()) {
if (contentNeeded) {
try (final InputStream in = file.getInputStream()) {
sendContent(in, response);
}
}
}
else if (ranges.size() > 1) {
response.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED);
renderer.renderErrorPage(request, response, file.getResourceStoreRequest(), new UnsupportedOperationException(
"Multiple ranges not yet supported!"));
}
else {
final Range<Long> range = ranges.get(0);
if (!isRequestedRangeSatisfiable(file, range)) {
response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
response.setHeader("Content-Length", "0");
response.setHeader("Content-Range", "bytes */" + file.getLength());
return;
}
final long bodySize = range.upperEndpoint() - range.lowerEndpoint();
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
response.setHeader("Content-Length", String.valueOf(bodySize));
response.setHeader("Content-Range",
range.lowerEndpoint() + "-" + range.upperEndpoint() + "/" + file.getLength());
if (contentNeeded) {
try (final InputStream in = file.getInputStream()) {
in.skip(range.lowerEndpoint());
sendContent(limit(in, bodySize), response);
}
}
}
}
}
最后幸好我们的请求在到Nexus之前有一个Apache proxy,根据http1.1标准,range request必须是client先发送range 请求,如果服务器支持
那么才返回状态嘛206和部分数据。所以最后我在proxy中把range header 强行去掉。这样服务器就不会返回206,而是返回200了.
也没有content-range header返回了,所以插件就会按照老实的方式,等待下载完成,然后渲染打开PDF文件.
最后的解决方案就是在Apache中增加如下配置.
LoadModule headers_module modules/mod_headers.so
RequestHeader unset Range
Failed to load PDF in chrome/Firefox/IE的更多相关文章
- Chrome系列 Failed to load resource: net::ERR_CACHE_MISS
在IE/FF下没有该错误提示,但在Chrome下命令行出现如下错误信息: Failed to load resource: net::ERR_CACHE_MISS 该问题是Chrome浏览器开发工具的 ...
- atom markdown转换PDF 解决AssertionError: html-pdf: Failed to load PhantomJS module
atom编辑器markdown转换PDF 解决AssertionError: html-pdf: Failed to load PhantomJS module. You have to set th ...
- 怎么解决Chrome浏览器“Failed to load resource: net::ERR_INSECURE_RESPONSE”错误?
用科学方法安装的arcgisServer,需要修改系统时间,但是修改了系统时间,可能会出各种问题, office 不能正确验证,chrome 不能正常使用,访问网页, 如果直接输入本地地址进行访问的话 ...
- Selenium IE6 Failed to load the library from temp directory: C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\IED1C1.tmp
项目中用到了使用Selenium打开IE浏览器.前期都是基于IE8+.Firefox.Chrome.项目后期开始现场测试时发现大部分客户还都是使用的Windows XP + IE6.结果可想而知,直接 ...
- Failed to load resource: net::ERR_CACHE_MISS
Failed to load resource: net::ERR_CACHE_MISS 译为开发人员工具载入缓存的时候,说找不到资源. 原因是你先打开页面,然后打开chrome的开发人员工具.而页面 ...
- java.lang.IllegalStateException: Failed to load ApplicationContext selenium 异常 解决
WARN <init>, HHH000409: Using org.hibernate.id.UUIDHexGenerator which does not generate IETF R ...
- atom markdown报错:AssertionError: html-pdf: Failed to load PhantomJS module.
今天安装markdown-pdf之后运行的时候报错: AssertionError: html-pdf: Failed to load PhantomJS module. You have to se ...
- Failed to load slave replication state from table mysql.gtid_slave_pos: 1146: Table 'mysql.gtid_slave_pos' doesn't exist
http://anothermysqldba.blogspot.com/2013/06/mariadb-1003-alpha-install-on-fedora-17.html MariaDB 10. ...
- elasticsearch按照配置时遇到的一些坑 [Failed to load settings from [elasticsearch.yml]]
这里整理几个空格引起的问题. 版本是elasticsearch-2.3.0 或者elasticsearch-rtf-master Exception in thread "main" ...
随机推荐
- Spring声明式事务配置管理方法
环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add ...
- HTML中为何P标签内不可包含块元素?
起因:在做项目时发现原本在DW中无误的代码到了MyEclipse6.0里面却提示N多错误,甚是诧异.于是究其原因,发现块级元素P内是不能嵌套DIV的. 深究:我们先来认识in-line内联元素和blo ...
- Solve Error Debug Assertion Failed Expression vector iterators incompatible Using PCL in Release Mode of VS2010
When using PCL 1.4.0 in the release mode building under VS2010, we might sometime get the error &quo ...
- HTML&CSS----练习做网页
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- iisNS 安装程序的思路
1. 安装程序的目录和 frontEnd一个目录,通过判断是否存在 common/config/db.php 来验证是否已经安装过,如果已经安装过,该文件会自动生成 2. 如果没有安装过,则跳转到 ...
- iOS dispatch_source_t的理解
Dispatch Source是GCD中的一个基本类型,从字面意思可称为调度源,它的作用是当有一些特定的较底层的系统事件发生时,调度源会捕捉到这些事件,然后可以做其他的逻辑处理,调度源有多种类型,分别 ...
- 去除GHOST版系统自带的2345流氓软件
话说2345真心流氓 用户想用你 自然不会删你 你这样强制性的 反而引起反感 应该是软件劫持性的捆绑 所以非常难起清除 最方便的方法就是 下载个 黄山IE修复专家 先把IE修复好 然后删除预安装 ...
- 样条曲线的Fortran程序
subroutine basis_function_b_val ( tdata, tval, yval ) ! !******************************************* ...
- 用Delphi“遥控”按钮
很多情况下,我们需要在程序中实现这样的功能:在自编写的程序里控制另外一软件中的某个按钮被按下.比如,有一天你在聊QQ时觉得烦了,那么就想写程序来帮你按下“发送”按钮,省得你自己一次次动手了.那么,这个 ...
- jquerymobile动态添加元素之后不能正确渲染解决方法
jquerymobile动态添加元素之后有些不能被正确渲染的解决方法: listview: 添加 jq(".detail").listview(&quo ...