Cowboy2静态文件处理器:能否修改浏览器下载文件名?
Yes, absolutely! You can control the filename that browsers see when downloading static files in Cowboy2, and also fix the unwanted .dms suffix issue. Here's how to do it:
Why the .dms Suffix Appears
First, let's address the .dms problem: this usually happens when Cowboy serves a file with a generic application/octet-stream Content-Type header. Browsers (especially older Safari versions) may not recognize this type and append .dms as a default extension. Fixing this requires setting the correct Content-Type for your files.
Approach 1: Configure Cowboy's Built-in Static Handler
Cowboy's cowboy_static module allows you to customize headers like Content-Disposition (which controls the download filename) and Content-Type via callback functions. Here's a sample route configuration:
{"/static/[...]", cowboy_static, [ {directory, {priv_dir, your_app_name, "static"}}, % Customize Content-Type to avoid .dms suffix {content_type, fun(_Req, Path) -> case filename:basename(Path) of "123" -> <<"text/plain">>; % Set correct type for your file % Fallback to Cowboy's default mimetype detection for other files _ -> cowboy_mimetypes:all(_Req, Path) end end}, % Set custom download filename {content_disposition, fun(_Req, Path) -> case filename:basename(Path) of "123" -> {attachment, "123.txt"}; % Specify desired filename % For other files, use inline display or default attachment _ -> inline end end} ]}
Key Details:
{content_disposition, Fun}: The function returns eitherinline(display in browser),attachment(download with original filename), or{attachment, DesiredFilename}(download with custom name).content_typecallback: Ensures the browser recognizes the file type, eliminating the.dmsguesswork.
Approach 2: Create a Custom Handler for Full Control
If you need more flexibility (like dynamic filename mappings or additional logic), build a custom handler module:
-module(custom_file_handler). -export([init/2]). init(Req0, State) -> % Get the requested path Path = cowboy_req:path(Req0), DiskFilePath = filename:join([code:priv_dir(your_app_name), "static", filename:basename(Path)]), case file:read_file_info(DiskFilePath) of {ok, _FileInfo} -> % Map disk filename to desired download name DisplayFilename = case filename:basename(DiskFilePath) of "123" -> "123.txt"; % Add more mappings here as needed Other -> Other end, % Set correct Content-Type based on display filename ContentType = case DisplayFilename of "123.txt" -> <<"text/plain">>; _ -> cowboy_mimetypes:all(Req0, DisplayFilename) end, % Set response headers Req1 = cowboy_req:set_resp_header(<<"content-type">>, ContentType, Req0), Req2 = cowboy_req:set_resp_header(<<"content-disposition">>, <<"attachment; filename=\"", DisplayFilename/binary, "\"">>, Req1), % Send the file to the client cowboy_req:reply(200, [], {sendfile, 0, 0, DiskFilePath}, Req2, State); {error, enoent} -> % Handle missing files cowboy_req:reply(404, [], <<"File not found">>, Req0, State) end.
Then add this handler to your route list:
{"/custom-files/[...]", custom_file_handler, []}
Testing the Solution
After updating your configuration or adding the custom handler:
- Start your Cowboy server.
- Navigate to the file URL (e.g.,
http://your-server/static/123). - The browser should download the file as
123.txtwithout the.dmssuffix.
内容的提问来源于stack exchange,提问作者Andriy Drozdyuk

