Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

文件下载之二三事 #23

Open
tiodot opened this issue Jul 15, 2017 · 0 comments
Open

文件下载之二三事 #23

tiodot opened this issue Jul 15, 2017 · 0 comments

Comments

@tiodot
Copy link
Owner

tiodot commented Jul 15, 2017

起源

开发时,经常需要使用别人提供的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
2. Data URI scheme
3. Data URLs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant