带有 Content-Disposition 的 HTTP 响应不会触发下载

D.S*_*ler 5 javascript xmlhttprequest http-headers axios msw

我使用msw来模拟自动化 FE 测试的后端响应。

我想为用户创建的数据创建导出功能。我正在POST向所需的路线发出请求,并希望返回带有 .csv 的响应;.pdf ;.xls 文件应自动下载。

我一直在寻找合适的方法来做到这一点,并遇到了Content-Disposition响应标头。

遗憾的是,响应没有触发保存对话框,也没有开始下载,但我找不到错误。


编辑:经过几次对话和一些独特的情况后,我决定为生成的 Blob 数据创建一个 ObjectURL,并通过调用强制下载window.open()

我更改了处理程序中的预期响应,并在 FE 中添加了相应的调用。

处理程序.js

rest.post('/mock/things/:thingId/export', async (req, res, ctx) => {
  const docType = req.headers.get('Content-type');
  const startDate = req.url.searchParams.get('startDate');
  const endDate = req.url.searchParams.get('endDate');
  const selected = req.body;

  const resDataString = 'testName,testLastName,\r\nDaniel,Schaller';
  const blob = new Blob([resDataString], { type: docType });
  const buffer = await blob.arrayBuffer();

  return res(
    ctx.status(200),
    ctx.set({
      'content-type': `${docType}`,
      'Content-length': buffer.byteLength.toString(),
    }),
    ctx.body(buffer),
    ctx.delay(),
  );
}),
Run Code Online (Sandbox Code Playgroud)

商店模块.js

async exportThings(ctx, exportData) {
  const {
    docType, startDate, endDate, selected,
  } = exportData;

  const res = await services.exportThingsForStuff(ctx.state.id, docType, startDate, endDate, selected);

  if (res.data !== undefined) {
    const dataBLOB = new Blob([res.data], { type: res.headers['content-type'] });
    window.open(URL.createObjectURL(dataBLOB));
  }
},
Run Code Online (Sandbox Code Playgroud)

让我向您展示一下工作流程:

某些组件.vue

async submitExport() {
  const exportDataFilters = {
    docType: this.docType,
    startDate: this.startDate,
    endDate: this.endDate,
    selected: this.selected,
  };

  const response = await this.$store.dispatch('exportThings', exportDataFilters);
  console.log(response);
},
Run Code Online (Sandbox Code Playgroud)

商店模块.js

async exportThings(ctx, exportData) {
  const {
    docType, startDate, endDate, selected,
  } = exportData;

  return services.exportThingsForStuff(ctx.state.id, docType, startDate, endDate, selected);
},
Run Code Online (Sandbox Code Playgroud)

服务.js

export const exportThingsForStuff = async (thingsId, docType, startDate, endDate, pl) => axios.post(`/mock/things/${thingsId}/export`, pl, {
  headers: {
    'Content-type': docType,
  },
  params: {
    startDate,
    endDate,
  },
Run Code Online (Sandbox Code Playgroud)

最后是来自 handlers.js 的 MSW 响应函数

rest.post('/mock/things/thingId/export', (req, res, ctx) => {
  // Vars will be in use to mimic filter behavior, as soon as the download problem is solved
  const docType = req.headers.get('Content-type');
  const startDate = req.url.searchParams.get('startDate');
  const endDate = req.url.searchParams.get('endDate');
  const selected = req.body;


  
// Creating a test string and blobbing it.
const resDataString = 'testName,testLastName,\r\nJoe,Moe';
const blob = new Blob([resDataString], { type: 'text/csv' });

return res(
  ctx.status(200),
  ctx.set({
    'Content-Disposition': 'attachment; filename="things_export.csv"',
    'Content-Length': blob.size.toString(),
    'Content-Transfer-Encoding': 'binary',
    'Content-Type': 'text/csv',
  }),
  ctx.body(blob),
  ctx.delay(),
);
Run Code Online (Sandbox Code Playgroud)

}),

我找不到它的问题,因为响应看起来像预期的那样:

Request URL: http://localhost:8080/mock/things/101/export?startDate=&endDate=
Request Method: POST
Status Code: 200 OK (from service worker)
Referrer Policy: strict-origin-when-cross-origin

RESPONSE HEADERS
content-disposition: attachment; filename="things_export.csv"
content-length: 37
content-transfer-encoding: binary
content-type: text/csv
x-powered-by: msw
Run Code Online (Sandbox Code Playgroud)

lal*_*tin 0

据我了解,您正在使用 Javascript 应用程序链接的响应,对吧?在这种情况下,浏览器将不会打开下载对话框。您应该将用户重定向到链接以触发下载对话框。但是您想使用 POST 方法,而不是填写表单并以编程方式提交,而不是调用axios.post