HTTP下载文件名

63

请问如何将文件名分配给a-href文件下载?

<a href="http://localhost:8080/couch/getFile?dbName=xxx&file=test.xml">get-file</a>

右键点击并选择“另存为”:后台运行的服务将返回test.xml内容,用户可以将其保存到本地。但每次用户都需要输入文件名才能保存。相反,我想拉取test.xml。请问如何告诉浏览器将“test.xml”用作下载文件名?

在HTTP响应上设置标头是否有效?如果有效,可以告诉我如何实现吗?

4个回答

109

您需要添加HTTP响应头 "Content-Disposition"

Response.AppendHeader("content-disposition", "attachment; filename=\"" + fileName +"\"");

3
请注意,IE似乎将单引号视为文件名的一部分。 - Bruno
2
单引号不适用于文件名。请参考quoted-string - Markus Malkusch
1
我替换了单引号。 - vtortola
1
如果 filename 包含引号或反斜杠(在 UNIX 中允许),则会出现错误,因为它们需要进行转义。 - Flimm
2
不能使用引号对(转义)因为它会破坏现有的软件。相反,将“”转义为%22并保留反斜杠\,因为这是所有现有软件遵循的事实标准。例如,如果您上传名为foo"bar\的文件,则浏览器会发送filename="foo%22bar\"(在2019年的Mac上测试了Firefox和Chrome)。如果您尝试遵循RFC并将\"视为转义序列,则解析将失败。 - Tronic

40
HTTP头部Content-Disposition允许您建议一个文件名。

Content-Disposition响应头字段可以用于附加其他元数据,例如在本地保存响应有效负载时要使用的文件名。

如果您查看BNF,您会看到文件名被指定为quoted-string

引用字符串=(<"> *(qdtext | quoted-pair)<">)

这将是一个有效的示例:
Content-Disposition: attachment; filename="fname.ext"

请注意,单引号'无效。如果您需要在文件名中包含引号("),可以使用"。但是RFC-6266建议避免包含引号

避免在文件名参数的引号字符串形式中包含""字符,因为某些用户代理程序没有实现转义,并且""可能被视为非法路径字符。


1
在引用字符串中,如何转义文件名中的引号? - Flimm
2
quoted-pair 是 "" CHAR,其中 CHAR 包含 "."。所以 " 就可以实现这个功能。RFC 在其 BNF 中也指出了这一点:反斜杠字符 ("") 只能在引号字符串中用作单字符引用机制。 - Markus Malkusch
1
更新的RFC-6266建议:避免在文件名参数的引用字符串形式中包含“\”字符,因为某些用户代理未实现转义,并且“\”可以被视为非法路径字符。 - Markus Malkusch
1
如果您不想让浏览器强制下载,而这是我理解 OP 请求的内容,那么请使用 "inline" 而不是 "attachment" Content-Disposition: inline; filename="fname.ext" - Peter Brand

11

在现代浏览器中,您还可以在链接标签上使用下载属性:

<a href="http://localhost:8080/couch/getFile?dbName=xxx&file=test.xml" download="test.xml">
    get-file
</a>

你可以在 Can I use 上查看它的支持情况。


1

为特定语言(如UA、DE、RU等)设置UTF-8文件名。

Content-Disposition: Attachment; Filename*=UTF-8'en'an%20example

文档:

这里有一个有趣的示例: https://github.com/thephpleague/csv/blob/master/src/AbstractCsv.php

protected function sendHeaders(string $filename): void
{
    if (strlen($filename) !== strcspn($filename, '\\/')) {
        throw InvalidArgument::dueToInvalidHeaderFilename($filename);
    }

    $flag = FILTER_FLAG_STRIP_LOW;
    if (strlen($filename) !== mb_strlen($filename)) {
        $flag |= FILTER_FLAG_STRIP_HIGH;
    }

    /** @var string $filtered_name */
    $filtered_name = filter_var($filename, FILTER_UNSAFE_RAW, $flag);
    $filename_fallback = str_replace('%', '', $filtered_name);

    $disposition = sprintf('attachment; filename="%s"', str_replace('"', '\\"', $filename_fallback));
    if ($filename !== $filename_fallback) {
        $disposition .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
    }

    header('Content-Type: text/csv');
    header('Content-Transfer-Encoding: binary');
    header('Content-Description: File Transfer');
    header('Content-Disposition: '.$disposition);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接