“name”web pdf是否可以更好地在Acrobat中保存文件名?

时间:2008-09-29 22:49:45

标签: http pdf content-type acrobat

我的应用会生成供用户使用的PDF。 “Content-Disposition”http标头按照here的设置进行设置。这被设置为“inline; filename = foo.pdf”,这足以让Acrobat在保存pdf时将“foo.pdf”作为文件名。

但是,单击嵌入浏览器的Acrobat中的“保存”按钮后,要保存的默认名称不是该文件名,而是带有斜杠的URL更改为下划线。巨大而丑陋。有没有办法在Adobe中影响这个默认文件名?

网址中有一个查询字符串,这是不可协商的。这可能很重要,但在URL的末尾添加“& foo = / title.pdf”不会影响默认文件名。

更新2:我试过了两次

content-disposition  inline; filename=foo.pdf
Content-Type         application/pdf; filename=foo.pdf

content-disposition  inline; filename=foo.pdf
Content-Type         application/pdf; name=foo.pdf

(通过Firebug验证)可悲的是,没有工作。

示例网址

/bar/sessions/958d8a22-0/views/1493881172/export?format=application/pdf&no-attachment=true

转换为默认的Acrobat保存为

的文件名
http___localhost_bar_sessions_958d8a22-0_views_1493881172_export_format=application_pdf&no-attachment=true.pdf

更新3:Julian Reschke为这种情况带来了实际的洞察力和严谨性。请提出他的回答。 这似乎在FF(https://bugzilla.mozilla.org/show_bug.cgi?id=433613)和IE中被打破,但在Opera,Safari和Chrome中都可以使用。 http://greenbytes.de/tech/tc2231/#inlwithasciifilenamepdf

16 个答案:

答案 0 :(得分:10)

问题的一部分是相关的RFC 2183并没有真正说明如何处理“内联”和文件名的处置类型。

另外,据我所知,实际使用type = inline文件名的唯一UA是Firefox(参见test case)。

最后,插件API实际上可以提供这些信息并不明显(也许熟悉API的人可以详细说明)。

话虽这么说,我已经向Adobe人发送了一个指向这个问题的指针;也许合适的人会看看。

相关:请参阅draft-reschke-rfc2183-in-http中的尝试澄清HTTP中的内容处置 - 这是早期的工作正在进行中,反馈意见。

更新:我添加了test case,这似乎表明Acrobat reader插件不使用响应标头(在Firefox中),尽管插件API提供了对它们的访问。

答案 1 :(得分:9)

同样在 ContentType 中设置文件名。这应该可以解决问题。

context.Response.ContentType = "application/pdf; name=" + fileName;
// the usual stuff
context.Response.AddHeader("content-disposition", "inline; filename=" + fileName);

设置content-disposition标头后,还要添加content-length标头,然后使用binarywrite来传输PDF。

context.Response.AddHeader("Content-Length", fileBytes.Length.ToString());
context.Response.BinaryWrite(fileBytes);

答案 2 :(得分:9)

和你一样,我试过让它发挥作用。最后我放弃了这个想法,只是选择了解决方法。

我正在使用ASP.NET MVC Framework,因此我修改了该控制器/操作的路由,以确保提供的PDF文件是URI的位置部分的最后一部分(在查询字符串之前),并传递查询字符串中的所有其他内容。

例如:

旧URI:

http://server/app/report/showpdf?param1=foo&param2=bar&filename=myreport.pdf

新URI:

http://server/app/report/showpdf/myreport.pdf?param1=foo&param2=bar

结果标题看起来与您所描述的完全一样(内容类型是application / pdf,处理是内联的,文件名是标题的无用部分)。 Acrobat在浏览器窗口中显示它(不保存为对话框),如果用户单击Acrobat Save按钮,则自动填充的文件名是报告文件名。

一些注意事项:

为了使文件名看起来像样,它们不应该有任何转义字符(即没有空格等)......这有点限制。在这种情况下,我的文件名是自动生成的,之前有空格,在生成的保存对话框文件名中显示为'%20'。我只是用下划线替换了空格,结果很明显。

这不是最好的解决方案,但确实有效。这也意味着您必须拥有可用的文件名才能使其成为原始URI的一部分,这可能会破坏您的程序的工作流程。如果在生成PDF的服务器端调用期间当前正在从数据库生成或检索它,则可能需要将生成文件名的代码移动到javascript作为表单提交的一部分,或者如果它来自数据库,则将其设置为快速ajax调用以在构建导致内联PDF的URL时获取文件名。

如果您从表单上的用户输入中获取文件名,则应验证该文件名不包含转义字符,这会使用户烦恼。

希望有所帮助。

答案 3 :(得分:5)

尝试在任何其他参数之前将文件名放在URL的末尾。这对我有用。 http://www.setasign.de/support/tips-and-tricks/filename-in-browser-plugin/

答案 4 :(得分:4)

在ASP.NET 2.0中,从

更改URL
http://www. server.com/DocServe.aspx?DocId=XXXXXXX

http://www. server.com/DocServe.aspx/MySaveAsFileName?DocId=XXXXXXX

这适用于Acrobat 8​​,默认的SaveAs文件名现在为MySaveAsFileName.pdf

但是,您必须限制MySaveAsFileName中允许的字符数(不包括句号等)。

答案 5 :(得分:4)

Apache的mod_rewrite可以解决这个问题。

我的网络服务的端点位于/foo/getDoc.service。当然,Acrobat会将文件保存为getDoc.pdf。我在apache.conf中添加了以下几行:

LoadModule     RewriteModule         modules/mod_rewrite.so
RewriteEngine  on
RewriteRule    ^/foo/getDoc/(.*)$    /foo/getDoc.service     [P,NE]

现在,当我请求/foo/getDoc/filename.pdf?bar&qux时,它会被内部重写为/foo/getDoc.service?bar&qux,因此我正在访问Web服务的正确端点,但Acrobat认为它会将我的文件保存为{{1} }。

答案 6 :(得分:2)

如果您使用asp.net,则可以通过页面(url)文件名控制pdf文件名。 正如其他用户所写,Acrobat有点......当你按“保存”按钮选择pdf文件名时:它取名页面,删除扩展名并添加“.pdf”。 所以/foo/bar/GetMyPdf.aspx给出了GetMyPdf.pdf。

我找到的唯一解决方案是通过asp.net处理程序管理“动态”页面名称:

  • 创建一个实现IHttpHandler
  • 的类
  • 将web.config中的处理程序映射到类

Mapping1:所有页面都有一个共同的基数(MyDocument _):

<httpHandlers>  
<add verb="*" path="MyDocument_*.ashx" type="ITextMiscWeb.MyDocumentHandler"/>

Mapping2:完全免费的文件名(路径中需要一个文件夹):

<add verb="*" path="/CustomName/*.ashx" type="ITextMiscWeb.MyDocumentHandler"/>

这里有一些提示(pdf是使用iTextSharp动态创建的):
http://fhtino.blogspot.com/2006/11/how-to-show-or-download-pdf-file-from.html

答案 7 :(得分:1)

您可以尝试内联而不是附件:

Response.AddHeader("content-disposition", "inline;filename=MyFile.pdf");

我在之前的Web应用程序中使用了内联,该应用程序将Crystal Reports输出生成为PDF并将其在浏览器中发送给用户。

答案 8 :(得分:1)

我相信这已经在一种或另一种味道中提到过,但我会试着用我自己的话说出来。

而不是:

/bar/sessions/958d8a22-0/views/1493881172/export?format=application/pdf&no-attachment=true

我用这个:

/bar/sessions/958d8a22-0/views/1493881172/NameThatIWantPDFToBe.pdf?GeneratePDF=1

当请求进入时,我不会对请求进行“导出”处理,而是查看GeneratePDF = 1的URL。如果找到,我会运行“导出”中运行的任何代码,而不是允许我的系统尝试在位置/bar/sessions/958d8a22-0/views/1493881172/NameThatIWantPDFToBe.pdf中搜索和提供PDF。如果在URL中找不到GeneratePDF,我只是传输请求的文件。 (请注意,我不能简单地重定向到所请求的文件 - 否则我最终会无限循环)

答案 9 :(得分:1)

带保存和打开选项的文件下载对话框(PDF)

要记住的要点:

  1. 从服务
  2. 返回正确数组大小的流
  3. 根据流长度从流中读取具有正确字节长度的字节文件。
  4. 设置正确的内容类型
  5. 以下是读取流的代码,并打开PDF文件的“文件下载”对话框

    private void DownloadSharePointDocument()
    {
        Uri uriAddress = new Uri("http://hyddlf5187:900/SharePointDownloadService/FulfillmentDownload.svc/GetDocumentByID/1/drmfree/");
        HttpWebRequest req = WebRequest.Create(uriAddress) as HttpWebRequest;
        // Get response   
        using (HttpWebResponse httpWebResponse = req.GetResponse() as HttpWebResponse)
        {
            Stream stream = httpWebResponse.GetResponseStream();
            int byteCount = Convert.ToInt32(httpWebResponse.ContentLength);
            byte[] Buffer1 = new byte[byteCount];
            using (BinaryReader reader = new BinaryReader(stream))
            {
                Buffer1 = reader.ReadBytes(byteCount);
            }
            Response.Clear();
            Response.ClearHeaders();
            // set the content type to PDF 
            Response.ContentType = "application/pdf";
            Response.AddHeader("Content-Disposition", "attachment;filename=Filename.pdf");
            Response.Buffer = true;
            Response.BinaryWrite(Buffer1);
            Response.Flush();
           // Response.End();
        }
    }
    

答案 10 :(得分:0)

您可以随时拥有两个链接。一个在浏览器中打开文档,另一个下载它(使用不正确的内容类型)。这就是Gmail的功能。

答案 11 :(得分:0)

我被重定向到这里因为我有同样的问题。我也尝试了特洛伊霍华德的解决方法,但似乎没有用。

我在这个方法上做的方法是不再使用响应对象来动态写入文件。由于PDF已存在于服务器上,我所做的是重定向指向该PDF文件的页面。效果很好。

http://forums.asp.net/t/143631.aspx

我希望我的模糊解释能给你一个想法。

答案 12 :(得分:0)

我解决这个问题的方法(使用PHP)如下:

假设您的网址为SomeScript.php?id=ID&data=DATA,您要使用的文件为TEST.pdf

将网址更改为SomeScript.php/id/ID/data/DATA/EXT/TEST.pdf

最后一个参数是您希望Adobe使用的文件名(“EXT”可以是任何内容),这一点很重要。确保上面的字符串中没有特殊的字符,BTW。

现在,在SomeScript.php的顶部,添加:

$_REQUEST = MakeFriendlyURI( $_SERVER['PHP\_SELF'], $_SERVER['SCRIPT_FILENAME']);

然后将此函数添加到SomeScript.php(或您的函数库):

function MakeFriendlyURI($URI, $ScriptName) {

/* Need to remove everything up to the script name */
$MyName = '/^.*'.preg_quote(basename($ScriptName)."/", '/').'/';
$Str = preg_replace($MyName,'',$URI);
$RequestArray = array();

/* Breaks down like this
      0      1     2     3     4     5
    PARAM1/VAL1/PARAM2/VAL2/PARAM3/VAL3
*/

$tmp = explode('/',$Str);   
/* Ok so build an associative array with Key->value
   This way it can be returned back to $_REQUEST or $_GET
 */
for ($i=0;$i < count($tmp); $i = $i+2){
    $RequestArray[$tmp[$i]] = $tmp[$i+1];
}
return $RequestArray;       
}//EO MakeFriendlyURI

现在$_REQUEST(或$_GET,如果您愿意)可以像普通$_REQUEST['id']$_REQUEST['data']等一样访问

当您以内联方式发送内容时,Adobe将使用您想要的文件名作为默认保存或电子邮件信息。

答案 13 :(得分:0)

对于任何仍然关注此事的人,我使用了here找到的解决方案并且效果非常好。谢谢Fabrizio!

答案 14 :(得分:0)

贷记Vivek


Nginx

$this->_id

检查

location /file.pdf
{
    # more_set_headers "Content-Type: application/pdf; name=save_as_file.pdf";
    add_header Content-Disposition "inline; filename=save_as_file.pdf";
    alias /var/www/file.pdf;
}

Firefox 62.0b5(64位):确定。

Chrome 67.0.3396.99(64位):确定。

IE 11:无可奉告。

答案 15 :(得分:-1)

如果您的可执行文件是“get.cgi”

,请尝试此操作

http://server,org/get.cgi/filename.pdf?file=filename.pdf

是的,这完全是疯了。服务器上没有名为“filename.pdf”的文件,可执行文件get.cgi下有目录。

但似乎有效。服务器忽略filename.pdf,pdf阅读器忽略“get.cgi”