浏览器访问图片链接的不同行为,以及如何使用Web API实现
发现一个有意思的现象,在浏览器中访问不同网站的图片链接,有的在浏览器中直接显示,有的则自动下载到本地。显然这个是由不同的实现造成的,那么究竟怎样控制这种行为差异呢?搜了一下,一个比较通用的做法是通过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,看下是否真的是这样?真的如此,如此的简单!
/// <summary>
/// 访问文件资源
/// </summary>
/// <param name="id">文件名</param>
/// <param name="model">显示模式,默认在浏览器中显示</param>
/// <returns>返回文件资源</returns>
[HttpGet("{id}")]
public ActionResult 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 == "0" ? "inline;" : "attachment;")}filename=\"{id}\"");
//通过Http在浏览器中展示图片 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类型 以及 MDN | 多媒体容器格式。 或许你在处理返回值时需要类似这样的代码(由于即使最常见的文件类型,媒体类型也多如牛毛,所以这里枚举的情况只能仅供参考):
id = id.ToLower();
string contentType = "application/octet-stream";
if (id.EndsWith(".txt")) {
contentType = "text/plain";
} else if (id.EndsWith(".pdf")) {
contentType = "application/pdf";
//广泛支持的图片类型
} else if (id.EndsWith(".jpg") || id.EndsWith(".jpeg")) {
contentType = "image/jpeg";
} else if (id.EndsWith(".png")) {
contentType = "image/png";
} else if (id.EndsWith(".gif")) {
contentType = "image/gif";
} else if (id.EndsWith(".svg")) {
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")) {
contentType = "audio/mpeg";
} else if (id.EndsWith(".mp4")) {
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") || id.EndsWith(".docx")) {
contentType = "application/msword";
} else if (id.EndsWith(".xls") || id.EndsWith(".xlsx")) {
contentType = "application/vnd.ms-excel";
} else if (id.EndsWith(".ppt") || id.EndsWith(".pptx")) {
contentType = "application/vnd.ms-powerpoint";
}
return File(bytes, contentType);