google-chromenext.jshttpresponsehttp-get

Next.js: Prevent file (as Buffer) in response from being parsed as JSON


I have a server using the Next.js API, whence I want to send the frontend a .csv file encoded in a locale-specific encoding (Shift_JIS).

My server currently uses this approach:

download(res: NextApiResponse, buffer: Buffer, fileName: string) {
    res.status(200)
    res.setHeader('Content-Type', 'text/csv')
    res.setHeader('Content-Disposition', 'attachment; filename="' + fileName + '"')
    res.send(buffer)
}

Looking at the logs in the server debugger, it seems that this part is working correctly.

The frontend page uses this code:

try {
    const response = await api.getRequestCsv({
    // insert necessary parameters here
    })
    console.log('tried', response)
} catch (e) {
    console.log('caught', e)
}

The API object does: this.request<{ /* @format binary */ file?: File }, any >({ path: /safdsfa/download, method: 'GET', query: {code: '123'}, format: 'json', })

The GET request sent in api.getRequestCsv() resolves correctly, but when I console.log it, I get this (abridged for brevity and secrecy):

Response {
    data: null
    error: "Unexpected token '�', "�v���W�F�N"... is not valid JSON"
    body: ReadableStream
        locked: true
    bodyUsed: true
    ok: true
    status: 200
    statusText: "OK"
    type: "basic"
    url: // insert intended URL here
}

My suspicion is that the frontend receives the response and, somewhere, it parses the file as a UTF-8 JSON string when it should have downloaded the stream as a file as-is.

How can I force the frontend to download the file in the response as-is instead of assuming that it's a JSON string and parsing it when it shouldn't?


Solution

  • I've figured it out. The server expects to respond with a JSON Object that contains a file, instead of directly responding with a file. I rewrote the backend response to:

    download(res: NextApiResponse, buffer: Buffer, fileName: string) {
        res.status(200)
        res.setHeader('Content-Type', 'text/csv')
        res.setHeader('Content-Disposition', 'attachment; filename="' + fileName + '"')
        res.send({file: buffer}) // changed
    }
    

    and did some complicated things in the frontend to extract the buffer from there and download it locally.