浏览器访问图片链接的不同行为,以及如何使用Web API实现

发现一个有意思的现象,在浏览器中访问不同网站的图片链接,有的在浏览器中直接显示,有的则自动下载到本地。显然这个是由不同的实现造成的,那么究竟怎样控制这种行为差异呢?搜了一下,一个比较通用的做法是通过HTTP响应头Content-Disposition来实现控制,简单来说就是:

  1. 设置为inline则在浏览器中直接显示

    Content-Disposition: inline;

  2. 设置为attachment则自动下载到本地

    Content-Disposition: attachment;

  3. 设置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://*.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://*.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);
上一篇:884. 两句话中的不常见单词


下一篇:Codeforces Round #717 (Div. 2)-A. Tit for Tat-题解