发现一个有意思的现象,在浏览器中访问不同网站的图片链接,有的在浏览器中直接显示,有的则自动下载到本地。显然这个是由不同的实现造成的,那么究竟怎样控制这种行为差异呢?搜了一下,一个比较通用的做法是通过HTTP响应头Content-Disposition来实现控制,简单来说就是:
inline
则在浏览器中直接显示
Content-Disposition: inline;
attachment
则自动下载到本地
Content-Disposition: attachment;
filename
, 以固定保存对话框和自动下载时的默认文件名(包括文件扩展名,否则浏览器会使用默认扩展名.jfif
,参见 .jfif是什么文件,如何转换成.jpg格式?)
Content-Disposition: inline; filename="image.jpg"
参数的详细使用请参考 MDN | Content-Disposition 以及 简书 | HTTP知多少——Content-Disposition, 不再赘述。听上去似乎简单的不可思议,那我们简单实现一个Web API,看下是否真的是这样?真的如此,如此的简单!
[HttpGet("{id}")] public ActionResult<string> Get(string id, string model = "0") { var path = @$"D:\docs\{id}"; if (!System.IO.File.Exists(path)) { return NotFound(); } //添加响应头的方式 https://stackoverflow.com/questions/46183171/how-to-add-custom-header-to-asp-net-core-web-api-response Response.Headers.Add("Content-Disposition", $"{(model == "1" ? "attachment;" : "inline;")}filename=\"{id}\""); //通过webAPI实现显示图片: https://stackoverflow.com/questions/39177576/how-to-to-return-an-image-with-web-api-get-method Byte[] bytes = System.IO.File.ReadAllBytes(path); return File(bytes, "image/jpeg"); }
那如果要支持多种文件类型呢?比如最常见的: 纯文本, PDF, Word/Excel/PPT, 音视频文件, 压缩文件,一个简单的方式就是控制文件的MIME。参见 MDN | MIME类型, IANA | 媒体类型 以及 MDN | 多媒体容器格式。 或许你在处理返回值时需要类似这样的代码(由于即使最常见的文件类型,MIME类型也多如牛毛,所以这里枚举的情况只能仅供参考):
string contentType = "application/octet-stream"; if (id.EndsWith(".txt", StringComparison.OrdinalIgnoreCase)) { contentType = "text/plain"; } else if (id.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase)) { contentType = "application/pdf"; //Web广泛支持的图片类型 } else if (id.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || id.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)) { contentType = "image/jpeg"; } else if (id.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) { contentType = "image/png"; } else if (id.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) { contentType = "image/gif"; } else if (id.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)) { contentType = "image/svg+xml"; //对于音频或视频文件, 只有正确设置了MIME类型的文件才能被 <video> 或<audio> 识别和播放 //参见:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#importance_of_setting_the_correct_mime_type } else if (id.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)) { contentType = "audio/mpeg"; } else if (id.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase)) { contentType = "video/mp4"; //微软office文件,是专有文件类型,使用 application/octet-stream 作为特殊处理是不被允许的 //而且,即使通过浏览模式在浏览器中访问,浏览office文件还是会自动下载本地,此处只列举了最常见的类型 //参见:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#importance_of_setting_the_correct_mime_type } else if (id.EndsWith(".doc", StringComparison.OrdinalIgnoreCase) || id.EndsWith(".docx", StringComparison.OrdinalIgnoreCase)) { contentType = "application/msword"; } else if (id.EndsWith(".xls", StringComparison.OrdinalIgnoreCase) || id.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase)) { contentType = "application/vnd.ms-excel"; } else if (id.EndsWith(".ppt", StringComparison.OrdinalIgnoreCase) || id.EndsWith(".pptx", StringComparison.OrdinalIgnoreCase)) { contentType = "application/vnd.ms-powerpoint"; } return File(bytes, contentType);