使用静态处理程序服务时是否可以更改下载文件名?

Is it possible to change the download filename when serving with static handler?

在 cowboy2 中使用静态文件处理程序提供文件时,"download" 文件名是否可能与磁盘上的实际文件名不同?

例如,假设我正在提供静态文件“123”。当用户在浏览器中下载它时,是否可以将其显示为“123.txt”?

因为现在,我的所有文件名都会自动分配一个扩展名为“.dms”的文件名。

我不认为静态处理程序的正常操作是 return 您的浏览器下载的文件。

When the static handler fails to [recognize] the extension, it will send the file as application/octet-stream. A browser receiving such file will attempt to download it directly to disk.

稍微备份一下,http 响应几乎总是包含 Content-Type header,它指定发送到浏览器的内容类型,以便浏览器知道如何显示内容.内容的类型用 mime type 指定。包含典型 html 页面的响应具有如下所示的 Content-Type header:

Content-Type: text/html; charset=utf-8

text/html mime 类型告诉浏览器不要将文件显示为文本,而是 文本显示为 html。

Cowboy 查看请求文件的扩展名以确定在响应的 Content-Type header 中指定的 MIME 类型。如果文件没有扩展名,Cowboy 会将 mime 类型指定为 application/octet-stream,这会导致您的浏览器下载该文件。你的浏览器基本上说,"I have no idea how to display this binary data, so here, you take the file and figure out what to do with it."

如果所有没有扩展名的文件都是(纯)文本文件,那么您可以告诉牛仔为所有匹配路径的文件设置 text/plain 的 mime 类型:

hello_erlang/src/hello_erlang_app.erl:

-module(hello_erlang_app).
-behaviour(application).

-export([start/2]).
-export([stop/1]).

start(_Type, _Args) ->
    Dispatch = cowboy_router:compile([
        {'_', [
               {"/dog/[...]", cowboy_static, 
                    {
                        priv_dir, 
                        hello_erlang, 
                        "static/assets", 
                        [{mimetypes, {<<"text">>, <<"plain">>, []} }] %<**HERE
                    }
               },

               {"/please_upgrade_to_websocket", myws_handler, []} 
        ]}
    ]),

    {ok, _} = cowboy:start_clear(my_http_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch} }
    ),

    hello_erlang_sup:start_link().

stop(_State) ->
    ok.

Mime 类型使用语法 word1/word2,而 cowboy 采用您在此处指定的语法:

[{mimetypes, {<<"text">>, <<"plain">>, []} }]

并用正斜杠将两个单词连接起来以生成 mime 类型的 "text/plain"。

目录结构:

hello_erlang/priv/static/assets/
    file1
    file2
    file3

url:

http://localhost:8080/dog/file1

您还可以让 cowboy 调用自定义函数来设置文件的 mime 类型:

hello_erlang/src/hello_erlang_app.erl:

-module(hello_erlang_app).
-behaviour(application).

-export([start/2]).
-export([stop/1]).

start(_Type, _Args) ->
    Dispatch = cowboy_router:compile([
        {'_', [
               {"/dog/[...]", cowboy_static, 
                    {
                        priv_dir, 
                        hello_erlang, 
                        "static/assets", 
                        [{mimetypes, my_mime_setter, set_type}] %<** HERE  {mimetypes, MODULE, FUNCTION}
                    }
               },

               {"/please_upgrade_to_websocket", myws_handler, []} 
        ]}
    ]),

    {ok, _} = cowboy:start_clear(my_http_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch} }
    ),

    hello_erlang_sup:start_link().

stop(_State) ->
    ok.

hello_erlang/src/my_mime_setter.erl:

-module(my_mime_setter).
-export([set_type/1]).

set_type(Path) ->
    Fname = filename:basename(Path),
    TextFiles = [<<"file1">>, <<"file2">>],

    case filename:extension(Fname) of
        <<>> ->  %no extension found(Yeah, I thought this would be an empty list, too!)
            case lists:member(Fname, TextFiles) of
                true  -> {<<"text">>, <<"plain">>, []};
                false -> {<<"text">>, <<"html">>, []}
            end;

        Ext ->
            case Ext of 
                <<".html">> -> {<<"text">>, <<"html">>, []};
                <<".css">>  -> {<<"text">>, <<"css">>, []};
                <<".js">>   -> {<<"application">>, <<"javascript">>, []};
                _Other      -> {<<"application">>, <<"octet-stream">>, []}
            end
    end.

您可以使用这些文件测试自定义 MIME setter:

hello_erlang/priv/static/assets/file1:

<div><font color="red">red text</font></div>

hello_erlang/priv/static/assets/file4:

<div><font color="red">red text</font></div>

如果您请求第一个文件:

http://localhost:8080/dog/file1

mime 类型将设置为 text/plain,并且浏览器不会呈现 html,而是您会看到原始的 html。如果请求第二个文件:

http://localhost:8080/dog/file4

mime 类型将设置为 text/html,这将导致浏览器呈现文本,您应该会看到一些红色文本。

如果你想对有扩展名的文件下注,你可以写:

   _Ext ->
       cow_mimetypes:web(Fname)

cowboy 将使用其算法得出 mime 类型。