tiodot / tiodot.github.io

总结归纳--做的东西不是每一件都留到现在 但是能通过实践,收获了如何构建一套系统,一套工具的方法论
https://xchb.work
8 stars 0 forks source link

文件下载之二三事 #23

Open tiodot opened 7 years ago

tiodot commented 7 years ago

起源

开发时,经常需要使用别人提供的json数据,一般都是新建一个.json文件,然后拷贝相关数据进去。有时需要保存临时性的json数据时,这样做还是有点麻烦。于是乎在想,能否做一个web页面,能直接导出数据为json文件?

原理探索

前提

要实现web页面直接导出文件,至少需要知道:

  1. 怎么让浏览器的执行下载操作?
  2. 数据怎么保存到下载的文件中?

对于第一点: 在H5规范中,a标签新增了一个download属性,如果有该属性,点击链接则会下载文件。

<a href="https://www.baidu.com/" download="baidu.html">

当然也还有其他一些方式,例如创建一个iframe,然后设置其src属性;或者创建一个form表单,然后设置其action属性。无论还a标签,iframe标签还是form表单提交,都具有跳转新页面的能力,当然也可以使用window.open等来实现下载,那是否可以得出这样一个结论:凡是具有新开或者跳转页面标签,或者js代码都可以用来实现文件的下载?

对应第二点: 在开发过程中,经常会将一些小图标转化为base64格式,然后直接写到css代码中,以便减少前端页面请求。例如: group 30

其转化之后的base64(在线转换地址)字符串为:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAABGdBTUEAALGPC/xhBQAAAOZJREFUKBWtkjEKhDAQRX+ynbV4CCt7DyB4BUGwEb3FNl5B0EbwEF5DbawFO7HwBLrOsLNstabYgSST4c3PQL46r8AVwzCgbVtM00RXuK6LOI7heR7fZbvjFAk2TYOyLPHWll5orZHnOZIk4ZoJp/q+P9M0xXEcH6HvhETruuaSCfewLOs5zzM3+L6PqqoQRRGotiwLT73vO8Zx5BqBvzgVBMG5bRsLdl0Hx3E4X9cVYRhybts2nyacZvKPm6bflCiKAjQZLcoliDHl/v4pmnyWZRlbRCaSU2xDjCnHPiSBO8PKI3fcC7ugtLEwYCn9AAAAAElFTkSuQmCC

可以看到字符串开头有个data:image/png;base64, ,这个是链接的Data URI格式, 而image/png这个标识的不就是图片类型,类似可以将请求的Content-type设置为application/json,表示以json格式提交参数。像image/pngapplication/json这类统称为MIME(Multipurpose Internet Mail Extensions.)

Data URI

在html页面,经常会用到一些外部资源,像图标,样式等,一般这些资源都需要发送请求获得,即使是和html在同一个服务器,发送请求也得再次建立连接,下载资源等,当这类请求多了时就可能会影响页面的性能。于是对于一些小图标,小文件,可以将其转换为Data URI形式,然后直接包含在html页面中。其格式为:

 data:[<media type>][;base64],<data>

如果是文本类型数据,则不需要加base64,直接将数据拼凑在,之后。

data:,Hello%2C%20World!  // 默认是 text/plain 类型数据  Hello World

data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D // base64-encoded 的Hello World

其用法也很简单,和url一样,直接赋值即可:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAABGdBTUEAALGPC/xhBQAAAOZJREFUKBWtkjEKhDAQRX+ynbV4CCt7DyB4BUGwEb3FNl5B0EbwEF5DbawFO7HwBLrOsLNstabYgSST4c3PQL46r8AVwzCgbVtM00RXuK6LOI7heR7fZbvjFAk2TYOyLPHWll5orZHnOZIk4ZoJp/q+P9M0xXEcH6HvhETruuaSCfewLOs5zzM3+L6PqqoQRRGotiwLT73vO8Zx5BqBvzgVBMG5bRsLdl0Hx3E4X9cVYRhybts2nyacZvKPm6bflCiKAjQZLcoliDHl/v4pmnyWZRlbRCaSU2xDjCnHPiSBO8PKI3fcC7ugtLEwYCn9AAAAAElFTkSuQmCC">

MIME

MIME type简单的理解就是文件的类型,和文件后缀名的作用相差无几,只不过这个是用于互联网传输文件。最直观的体现就是请求头或者响应头中的Content-type字段。其格式分为两个部分,一个typesubtype:

type/subtype

这里的type可以理解为文件可以图片类的,文本类的等等。而subtype就是只某一类文件的具体类型或格式,像图片就可以分为jpg,jpeg(image/jpeg)、png(image/png)等,具体的可以参考MIME Types List

实现

依据上述探索的过程,首先创建一些html标签,用于输入需要保存的json数据,文件名等,同时创建一个隐藏的a标签用于提供下载操作。

<input type="text" id="file" placeholder="file name">
<button id="convert">保存为JSON文件</button>
<hr>
<textarea name="" id="json" cols="100" rows="30" placeholder="content"></textarea>
<a id="download" style="display:none"></a>

然后在js中,将数据拼凑成Data URI形式之后赋值为a标签的href属性上:

document.addEventListener('DOMContentLoaded', () => {
        const $ = document.querySelector.bind(document);
        const $download = $('#download');
        const $name = $('#file');
        $('#convert').onclick = (e) => {
            const json = $('#json').value;
            const dataStr = "data:application/json;charset=utf-8," + encodeURIComponent(json);
            $download.setAttribute('href', dataStr);
            $download.setAttribute('download', ($name.value || 'data') +  '.json');
            $download.click();
        }
    })

在线体验 PS: 如果设置a标签的download属性有加文件后缀,chrome浏览器会优先使用该后缀对应的MIME type,如果没有设置后缀名,会已经href中的Data URI中的MIME type 提供一个后缀名

工具:

  1. 图片base64在线转换
  2. 在线导出文本

    参考

    1.MIME Types List

  3. Data URI scheme
  4. Data URLs