简体   繁体   English

在客户端处理来自`res.download()`的响应(Rest api,快递)

[英]Handling the response from `res.download()` on the client side (Rest api, express)

So the express docs have a download function in the following form:所以快递文档有一个下载 function 格式如下:

res.download(cvUrl, cvName, function (err) {
  if (err) {
     // ...
  } else {
     // ...
  }
})

I think this would normally trigger the browser to download the file automatically, with the correct filename, as the response headers are correctly set and I'm receiving a file.我认为这通常会触发浏览器使用正确的文件名自动下载文件,因为响应标头设置正确并且我正在接收文件。 But I'm handling the download like this:但我正在处理这样的下载:

this.admin.getCv(cvUrl).then(cv => {
    const url = window.URL.createObjectURL(new Blob([cv]));
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', 'test'); // how can I access the filename here?
    document.body.appendChild(link);
    link.click();
})

Is it possible to access the filename (cvName) on the frontend?是否可以在前端访问文件名(cvName)? Adding it as a second parameter seemed like the obvious solution, but didn't work.添加它作为第二个参数似乎是显而易见的解决方案,但没有奏效。 Any hints would be great,任何提示都会很棒,

Thanks,谢谢,

Nick缺口

**Edit: **编辑:

import JRS from '../api/jrs';

export default class Admin {
    getCv (applicantId) {
        return JRS.get(`/admin/cvs/${applicantId}`);
    }
}

// JRS.js // JRS.js

import axios from 'axios';

export default axios.create({
    baseURL: 'http://localhost:8080',
    headers: {
        'Content-Type':  'application/json',
    },
    withCredentials: true
});

The download method adds a Content-Disposition header to the response, so you just need to read that. download方法将Content-Disposition header 添加到响应中,因此您只需阅读它。

It looks like your getCv function makes an HTTP request, extracts the body from the response, then resolves a promise with that body.看起来您的getCv function 发出 HTTP 请求,从响应中提取正文,然后用该正文解析 promise。

You'll need to modify the getCv function so it:您需要修改getCv function 使其:

  • Reads the Content-Disposition header (how you do that depends on which HTTP API you are using)读取Content-Disposition header (如何操作取决于您使用的是哪个 HTTP API)
  • Extracts the filename from it (something like contentDisposition.match(/filename=(.*)/) )从中提取文件名(类似于contentDisposition.match(/filename=(.*)/)
  • Includes that in the data you are resolving the promise with (which will probably mean passing an object containing the filename and body instead of just the body)包括在您正在解析 promise 的数据中(这可能意味着传递包含文件名和正文而不仅仅是正文的 object)

Then you'll need to change your then callback so it handles that object instead of expecting the body directly.然后您需要更改您的then回调,以便它处理 object 而不是直接期待正文。


That said, it would probably be easier to just link to the URL directly instead of fetching the data with JSON, converting it to a data: URL, generating a link and triggering a client on it.也就是说,直接链接到 URL 可能更容易,而不是使用 JSON 获取数据,将其转换为data: ZE6B391A8D2C4D45902A23A8B6585703 并在其上触发 DZZ 并在其上生成链接。

This works for accessing the filename and ext, and fixes the problem I was having with axios/streams/unreadable content, in case it helps anyone else.这适用于访问文件名和分机,并解决了我在 axios/streams/不可读内容方面遇到的问题,以防它帮助其他人。

For the unreadable content, it was important to add the responseType to the request.对于不可读的内容,将 responseType 添加到请求中很重要。

// Client side // 客户端

axios.get('http://localhost:4000/download', {responseType: 'blob'}).then(res => {
    downloadFile(res);
}).catch(err => console.log(err));

const downloadFile = (res) => {
    const contentDisposition = res.headers['content-disposition'];
    const fileName = contentDisposition.split(';')[1].split('=')[1];

    const url = window.URL.createObjectURL(new Blob([res.data]));
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', `${fileName}`);
    document.body.appendChild(link);
    link.click();
}

// Server // 服务器

app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:2000');
    res.setHeader('Access-Control-Expose-Headers', 'Content-Disposition');
    next();
});

app.get('/download', (req, res, next) => {
    const test = 'sample.doc';
    const fileUrl = path.join(__dirname, test);
    const fileName = path.basename(fileUrl);
    res.header('Content-Disposition', `attachment; filename=${fileName}`);
    const myReadableStream = fs.createReadStream(path.join(__dirname, test));
    res.status(200);
    myReadableStream.pipe(res);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM