2024_Hello_World
@2024_Hello_World

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Csv出力機能を実装したい

解決したいこと

CSV出力機能を実装したい
APIたたいた時点で自動でブラウザにCSVが出力される機能

仕様技術 vue.js
ライブラリ axios

解決方法を教えて下さい。

発生している問題・エラー

response.headerの中にfileNameが見当たらない

または、問題・エラーが起きている画像をここにドラッグアンドドロップ

スクリーンショット 2024-11-19(1).png

スクリーンショット 2024-11-19 104742.png

該当するソースコード

API呼んでいる箇所

  /**
   * postMigrationItem
   * @description 移行情報csvをダウンロード
   * @param requestId
   * @returns { Promise<void>}
   */
  const postMigrationItem = async (requestId: number | null): Promise<any> => {
    try {
      const response = await apiClient.post(`/migration/file/${requestId}`)
      const url = window.URL.createObjectURL(new Blob([response.data]))
      const link = document.createElement('a')
      link.href = url
      const contentDisposition = response.headers['Content-Disposition']
      const contentType = response.headers['Content-Type']
      console.log('contentHeaders:', response.headers)
      console.log('contentDisposition:', contentDisposition)
      console.log('contentType:', contentType)
      const fileName = contentDisposition
        ? contentDisposition.split('filename=')[1]
        : 'download.csv'
      console.log('fileName:', fileName)
      link.setAttribute('download', fileName)
      document.body.appendChild(link)
      link.click()
      link.remove()
    } catch (error: unknown) {
      throw new Error('postMigrationItemでエラーが発生しました。')
    }
  }



const baseHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
  const requestId = Number(event.pathParameters?.requestId);

  if (!event.pathParameters?.requestId) {
    return createResponse(JSON.stringify({ error: 'Invalid or missing requestId' }));
  }

  const result = await transferDownload(requestId);
  console.log('result.base64Data:', result.base64Data)
  console.log('result.csvFileName:', result.csvFileName)
  if (result) {
    return createBinaryCsvResponse(result.base64Data, result.csvFileName);
  } else {
    return createResponse(
      JSON.stringify({
        statusCode: 201,
        body: JSON.stringify({ message: 'Nothing update transfer date by requestIds' }),
      }),
    );
  }
};
export const lambdaHandler = middy(baseHandler).use(httpErrorHandlerMiddleware());

export function createBinaryCsvResponse(body: string, fileName: string) {
  return {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Headers':
        'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
      'Content-Type': 'text/csv',
      'Content-Disposition': `attachment; filename='${fileName}'`,
    },
    body: body,
    isBase64Encoded: true,
  };
}

自分で試したこと

・デバッガーでログの検証
・const contentDisposition = response.headers['Content-Disposition'] const contentType = response.headers['Content-Type']
の部分を小文字に変更→変化なし

0

3Answer

同じような内容でこちらと他方と2つあるので、終わっていたり変わっていたりするのであれば、どちらかだけでもクローズしておいてもらないでしょうか

0Like

Comments

  1. そっちは既にクローズしているのでは……?
    (どういう解決策を講じたかは私も気にはなりますが。

  2. あ、すみません、きづきませんでした・・・失礼しました。

解決方法を教えて下さい。

何を解決したいのですか?

「発生している問題・エラー」が、

response.headerの中にfileNameが見当たらない

ということですが、API の応答ヘッダが Content-Disposition: attachment; filename=xxx.csv; だった場合、xxx.csv が分かればいいのですか?

やりたいことは、

APIたたいた時点で自動でブラウザにCSVが出力される機能

ということだそうですが、それはほぼ実装できていて、xxx.csv が分かればすべて解決という話でしょうか?

違うとすると何でしょう?


【追記】

axios ではなくて fetch を使って、同一ドメインでですが試してみました。

下の画像のように応答ヘッダに Content-Disposition が含まれていれば、

fiddler2.jpg

以下の様なコードで response.headers.get("content-disposition") を使って、

const fetchApi = async () => {
    const url = "/Download/VirtualFileResult";
    const filename = "testfetch";

    const response = await fetch(url);
    if (response.ok) {
        const cd = response.headers.get("content-disposition");
        console.log(cd);
        const blob = await response.blob();
        const a = document.createElement("a");
        const url = window.URL;
        a.href = url.createObjectURL(new Blob([blob],
            { type: blob.type }));
        document.body.appendChild(a);
        a.style = "display: none";
        a.download = filename + ".pdf";
        a.click();
    } else {
        // エラー処理(省略)
    }
};

以下の通り取得できます。

result.jpg

応答ヘッダに Content-Disposition は含まれてますか? 質問に貼った画像では Content-Disposition のみならず Content-Type も undefined という結果に見えます。応答ヘッダはどうなってますか?

クロスドメインの場合どうなるかは試してないので不明ですが、質問のコードにあるポスト先 /migration/file/${requestId} は同一ドメインのように見えます。どうなんでしょう?

0Like

Your answer might help someone💌