如何使用 API 路由在 Next.js 上下载文件

Jos*_*Joe 2 download next.js

我正在使用 next.js。我有一个第 3 方服务,我需要从中检索 PDF 文件。该服务需要一个我不想在客户端公开的 API 密钥。

这是我的文件

/api/getPDFFile.js ...

  const options = {
    method: 'GET',
    encoding: 'binary',
    headers: {
      'Subscription-Key': process.env.GUIDE_STAR_CHARITY_CHECK_API_PDF_KEY,
      'Content-Type': 'application/json',
    },
    rejectUnauthorized: false,
  };

  const binaryStream = await fetch(
    'https://apidata.guidestar.org/charitycheckpdf/v1/pdf/26-4775012',
    options
  );
  
  return res.status(200).send({body: { data: binaryStream}}); 


Run Code Online (Sandbox Code Playgroud)

页面/getPDF.js

   <button type="button" onClick={() => {
  fetch('http://localhost:3000/api/guidestar/charitycheckpdf',
    {
      method: 'GET',
      encoding: 'binary',
      responseType: 'blob',
    }).then(response => {
      if (response.status !== 200) {
        throw new Error('Sorry, I could not find that file.');
      }
      return response.blob();
    }).then(blob => {
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.style.display = 'none';
      a.href = url;
      a.setAttribute('download', 'test.pdf');
      document.body.appendChild(a);
      a.click();
      window.URL.revokeObjectURL(url);
    })}}>Click to Download</button>
Run Code Online (Sandbox Code Playgroud)

单击该按钮可下载文件,但当我打开它时,我看到错误消息“无法加载 PDF 文档”。

brc*_*-dd 5

您似乎正在使用node-fetch. 所以,你可以做这样的事情:

// /pages/api/getAPI.js

import stream from 'stream';
import { promisify } from 'util';
import fetch from 'node-fetch';

const pipeline = promisify(stream.pipeline);
const url = 'https://w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf';

const handler = async (req, res) => {
  const response = await fetch(url); // replace this with your API call & options
  if (!response.ok) throw new Error(`unexpected response ${response.statusText}`);

  res.setHeader('Content-Type', 'application/pdf');
  res.setHeader('Content-Disposition', 'attachment; filename=dummy.pdf');
  await pipeline(response.body, res);
};

export default handler;
Run Code Online (Sandbox Code Playgroud)

然后从客户端:

// /pages/index.js

const IndexPage = () => <a href="/api/getPDF">Download PDF</a>;
export default IndexPage;
Run Code Online (Sandbox Code Playgroud)

CodeSandbox 链接(在新选项卡中打开部署的 URL以查看它的工作情况)

参考:

PS:我认为在这种情况下不需要太多的错误处理。如果您希望向用户提供更多信息,则可以。但是这么多代码也可以正常工作。如果出现错误,文件下载将失败,显示“服务器错误”。另外,我认为不需要先创建blobURL。您可以直接在您的应用程序中下载它,因为 API 是同源的。


早些时候我使用过 request,也张贴在这里以防万一有人需要它:

import request from 'request';
const url = 'https://w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf';
export default (_, res) => { request.get(url).pipe(res); };
Run Code Online (Sandbox Code Playgroud)