• 浏览器访问图片链接的不同行为,以及如何使用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,看下是否真的是这样?真的如此,如此的简单!

    /// <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);
    
  • 相关阅读:
    golang模拟动态高优先权优先调度算法
    【2019腾讯暑期实习生正式批笔试1,2】
    golang优先队列
    git常见操作
    小L的试卷
    Unable to connect to the Redgate Client Service. Sql Prompt 报错不能用解决
    未能加载文件或程序集“Microsoft.VisualStudio.Enterprise.AspNetHelper, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”或它的某一个依赖项。系统找不到指定的文件。
    LumiSoft 邮件操作删除(无法删除解决方法)
    .net MVC 项目中 上传或者处理进度获取方案
    C# mvc Request 请求过长报404错误的解决思路分析
  • 原文地址:https://www.cnblogs.com/makesense/p/15780098.html
Copyright © 2020-2023  润新知