43

我的应用程序生成 PDF 供用户使用。“Content-Disposition”http 标头的设置如此所述。这设置为“inline; filename=foo.pdf”,这足以让 Acrobat 在保存 pdf 时将“foo.pdf”作为文件名。

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

URL 中有一个查询字符串,这是不可协商的。这可能很重要,但在 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

4

16 回答 16

11

还要在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);
于 2008-09-30T00:28:57.957 回答
11

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

此外,据我所知,唯一真正使用 type=inline 文件名的 UA 是 Firefox(请参阅测试用例)。

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

话虽如此,我已向 Adob​​e 人员发送了指向此问题的指针;也许合适的人会看看。

相关:请参阅在draft-reschke-rfc2183-in-http中澄清 HTTP 中的 Content-Disposition 的尝试——这是正在进行的早期工作,感谢反馈。

更新:我添加了一个测试用例,这似乎表明 Acrobat 阅读器插件不使用响应标头(在 Firefox 中),尽管插件 API 提供了对它们的访问。

于 2009-03-21T11:20:48.147 回答
9

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

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

例如:

旧 URI:

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

新的 URI:

http://server/app/report/showpdf/myreport.pdf?param1=foo¶m2=bar

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

几点考虑:

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

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

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

希望有帮助。

于 2008-12-03T22:47:26.610 回答
5

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

于 2011-12-02T19:12:57.603 回答
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(无句点等)。

于 2010-12-26T16:13:20.417 回答
4

Apachemod_rewrite可以解决这个问题。

我有一个端点为 的 Web 服务/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 认为它将我的文件保存为filename.pdf.

于 2011-07-27T23:36:51.583 回答
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

于 2009-05-22T14:35:17.197 回答
1

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

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

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

于 2008-09-30T01:54:04.323 回答
1

我相信这已经以一种或另一种方式提到过,但我会尝试用我自己的话来陈述它。

而不是这样:

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

我用这个:

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

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

于 2009-05-14T16:54:24.843 回答
1

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

要记住的要点:

  1. 从服务返回具有正确数组大小的流
  2. 根据流长度从流中读取具有正确字节长度的字节数组。
  3. 设置正确的内容类型

这是读取流的代码并打开 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();
    }
}
于 2010-12-18T07:42:50.937 回答
0

你总是可以有两个链接。一个在浏览器中打开文档,另一个用于下载(使用不正确的内容类型)。这就是 Gmail 所做的。

于 2008-09-29T23:35:12.893 回答
0

我被重定向到这里,因为我有同样的问题。我也尝试了 Troy Howard 的解决方法,但它似乎不起作用。

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

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

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

于 2009-01-14T01:52:44.460 回答
0

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

假设您的 URL 是SomeScript.php?id=ID&data=DATA并且您要使用的文件是TEST.pdf.

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

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

现在,在顶部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如果您愿意)可以像 normal $_REQUEST['id']$_REQUEST['data']等一样访问。

当您在线发送文件时,Adobe 将使用您想要的文件名作为默认另存为或电子邮件信息。

于 2009-11-26T20:21:49.407 回答
0

对于仍在关注此问题的任何人,我使用了此处找到的解决方案,并且效果非常好。谢谢法布里齐奥!

于 2010-01-06T19:37:51.583 回答
0

归功于Vivek


Nginx

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;
}

检查与

curl -I https://example.com/file.pdf

Firefox 62.0b5(64 位):好的。

Chrome 67.0.3396.99(64 位):好的。

IE 11:没有评论。

于 2018-07-12T10:22:18.633 回答
-1

试试这个,如果你的可执行文件是“get.cgi”

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

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

但它似乎工作。服务器忽略 filename.pdf,pdf 阅读器忽略“get.cgi”

于 2009-04-06T22:38:11.847 回答