木灵鱼儿

木灵鱼儿

阅读:243

最后更新:2022/10/05/ 11:35:20

url文件的下载

前言

以前写过一篇《目前前端下载文件的最佳实践》的文章,虽然这个文章是我经过工作实践得出得,但是直到今天我才发现,原来不止如此,根据我目前的知识,可以把文件下载分为两类:

  1. 接口返回文件流
  2. 文件下载地址

之前分析的文章仔细一想,其实都在做一个事情:读取文件流再手动转文件进行本地下载

首先我们需要知道,我们的a链接下载其实并没有问题,本来是不需要读取文件流的,但是后端对头信息的了解不多,导致下载文件的链接是一个预览的头信息,这就导致我们a链接无法直接通过点击直接下载,反而是直接打开了这个文件。

这带来的结果就是我们会认为图片啊,pdf这些浏览器可以直接打开的文件,并不会触发下载,而是预览,因为我们很少去怀疑这是不是后端的问题。

为了解决这个问题,我们前端的做法就是通过其它方式读取文件流,然后再自己手动保存文件达到下载文件的效果。具体的做法之前文章就有分享,这里就不多说了。

但是,我们并不需要这么做,一个正宗的文件下载,它的表现应该就是:

  1. 我们触发一个api请求,后端返回响应,浏览器直接弹出保存文件弹出
  2. 用户点击a链接下载,后端返回响应,浏览器直接弹出保存文件弹出

而文件流的下载,这种其实会涉及到文件的最新啊,或者权限相关的东西,所以各有千秋,但是正宗的还是上述2点。

怎么做呢?

教程

文件预览

文件的预览,也就是后端错误的文件下载设置,他的头信息有两条:

  • Content-Disposition
  • Content-Type

例子:

Content-disposition: inline
Content-Type: image/jpeg

inline表示消息体会以页面的一部分或者整个页面的形式展示,也就是预览,这个需要配合Content-Type一起使用,来告诉浏览器预览的是一个什么文件。

按道理还有一个头信息Content-Length,他用来表示文件的大小,但是这里只关心下载,所以就不过多赘述。

当我们的下载出现预览时,可以看看响应头是不是这两个。

文件下载(不携带文件名)

头信息设置为:

Content-Disposition: attachment

表示消息体需要被下载,而下载的文件名取决于url,比如你访问的url是:

http://localhost:3000/file/1.jpg

那么文件名就是:1.jpg

而文件格式浏览器会通过Content-Type来自动添加,比如我请求:

http://localhost:3000/file/1

但是头信息是:

Content-Disposition: attachment
Content-Type: image/jpeg

浏览器还是会识别为:1.jpg

文件下载(带文件名)

Content-Disposition: attachment;filename="filename.jpg"

这个就需要后端动态控制头信息了,比如我设置为:

Content-Disposition: attachment;filename="123.jpg"

访问下载地址:http://localhost:3000/file/1.jpg

下载的文件将是:123.jpg

由于是指定了文件名,所以浏览器不会根据Content-Type追加文件格式,如果后端的filename的文件格式不对,也会按照这个来进行下载。

koa源码

提供一下个人的测试源码:

server.js

const Koa = require("koa");
const Router = require("koa-router");
const fs = require("fs");
const path = require("path");
const static = require("koa-static");
const send = require("koa-send");

const app = new Koa();
const router = new Router();

router.get("/file/:name", async (ctx) => {
  const name = ctx.params.name;
  const path = `download/${name}`;
  ctx.attachment(path);
  ctx.set("Content-disposition", `attachment;filename="123.jpg"`);
  await send(ctx, path);
});

app.use(static(path.join(__dirname)));

app.use(router.routes());
app.listen(3000);

download目录与server.js同级。

总结

至此应该可以明白前端下载文件竟然如此简单,再也不用头疼的想办法去下载文件了,我们也可以据理力争前端权益了(明明是后端的问题)。

版权申明

本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。

关于作者

站点职位 博主
获得点赞 1
文章被阅读 243

相关文章