使用Next.js和MongoDB上传和下载PDF文件

b1payxdu  于 2022-11-22  发布在  Go
关注(0)|答案(1)|浏览(271)

我正在尝试制作上传和下载PDF文件的应用程序。正如标题中提到的,我使用MongoDB和Next.js。我的文件将小于16 MB,所以我可以将它们作为一个完整的二进制文件存储。上传似乎工作正常,但我不确定(数据库中有文件内容,似乎很奇怪,是PDF文件)。但下载返回PDF,无法打开/加载或为空。
上传:客户端

const uploadHandler = async (e, fileName) => {
        const Tempfile = e.target.files[0]
        if (!Tempfile) {
            return
        }
        // check file size
        const size = parseInt(((Tempfile.size/1024)/1024).toFixed(4))
        if (size > 16) {
            popupHandler("File too large!")
        }
        // rename file from https://stackoverflow.com/questions/21720390/how-to-change-name-of-file-in-javascript-from-input-file
        let file =  new File([Tempfile.slice(0, Tempfile.size, 'application/pdf')], `${fileName}.pdf`, {type: 'application/pdf'});
        // create formData
        const form = new FormData();
        form.append('myFile', file)
        // upload
        const response = await fetch('/api/upload', {
            method: 'POST',
            body: form
        })
        if (response.status === 200) {
            console.log('succ')
        }
    }

服务器(Next.js API):

import { NextApiRequest, NextApiResponse } from "next/types";
import { connectToDatabase } from "../../../../database/database";
import { IncomingForm } from 'formidable'
import { promises as fs } from 'fs'

// https://stackoverflow.com/questions/60465564/create-upload-files-api-in-next-js

export const config = {
  api: {
    bodyParser: false,
  }
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    if (req.method !== 'POST') {
        return res.status(400).json({message: 'Bad request'});
    }

    const client = await connectToDatabase();
    const database = client.db("Test").collection("Files");

    try {

        const data: any = await new Promise((resolve, reject) => {
            const form = new IncomingForm()
            
            form.parse(req, async (err, fields, files) => {
                if (err) return reject(err)
                resolve({ fields, files })
            })
        })

        const contents = await fs.readFile(data?.files?.myFile.filepath, {
            encoding: 'utf8',
        })
        const FILE = {
            "fileName": data?.files?.myFile.originalFilename,
            "content": contents
        }

        await database.insertOne(FILE)

    } catch(e) {
        console.error(e)
        client.close();
        return res.status(400).json({message: "Uploading failed!"});

    }
    
    client.close();
    return res.status(200).json({ message: 'succ!' })
}

下载:
委托单位:

const downloadHandler = async (fileName) => {
        const response = await fetch('/api/download', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({fileName})
        })
        if (response.status !== 200) {
            return
        } else {
            // https://stackoverflow.com/questions/68490546/how-to-download-a-file-on-next-js-using-an-api-route
            const data = await response.blob()
            const url = window.URL.createObjectURL(data)
            const a = document.createElement('a')
            a.style.display = 'none'
            a.href = url
            a.setAttribute('download', `${fileName}.pdf`)
            document.body.appendChild(a)
            a.click()
            window.URL.revokeObjectURL(url)
            document.body.removeChild(a)
        }
    }

伺服器:

import { NextApiRequest, NextApiResponse } from "next/types";
import { connectToDatabase } from "../../../../database/database";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    if (req.method !== 'POST') {
        return res.status(400).json({message: 'Bad request'});
    }

    const { fileName } = req.body

    const client = await connectToDatabase();
    const database = client.db("Test").collection("Files");

    const result = await database.findOne({ fileName: `${fileName}.pdf` }, { projection: {_id: 0} } );

    if (!result) {
        client.close();
        return res.status(400).json({message: "File not found!"});
    } 
    
    client.close();
    return res.status(200).setHeader('Content-Type', 'application/pdf').setHeader("Content-Disposition", "attachment; filename=" + result.fileName).send(result.content);

}

您能向我解释一下为什么我无法打开这些PDF文件或之后看不到它们的内容吗?提前感谢

avwztpqn

avwztpqn1#

最后我调试了一下,下面是给我的程序员同事的结果代码:
客户端上传:

const uploadHandler = async (e, fileName) => {
    const Tempfile = e.target.files[0]
    if (!Tempfile) {
        return
    }
    // check file size
    const size = parseInt(((Tempfile.size/1024)/1024).toFixed(4))
    if (size > 16) {
        popupHandler("File too large!")
    }
    let file =  new File([Tempfile.slice(0, Tempfile.size, 'application/pdf')], `${fileName}.pdf`, {type: 'application/pdf'});
    const form = new FormData();
    form.append('myFile', file)
    const response = await fetch('/api/upload', {
        method: 'POST',
        body: form
    })
    if (response.status === 200) {
        console.log('succ')
    }
}

然后服务器上传:

import { NextApiRequest, NextApiResponse } from "next/types";
import { connectToDatabase } from "../../../../database/database";
import { IncomingForm } from 'formidable'
import { promises as fs } from 'fs'

export const config = {
  api: {
    bodyParser: false,
  }
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    if (req.method !== 'POST') {
        return res.status(400).json({message: 'Bad request'});
    }

    const client = await connectToDatabase();
    const database = client.db("Test").collection("Files");

    try {

        const data: any = await new Promise((resolve, reject) => {
            const form = new IncomingForm()
            
            form.parse(req, async (err, fields, files) => {
                if (err) return reject(err)
                resolve({ fields, files })
            })
        })

        const contents = await fs.readFile(data?.files?.myFile.filepath)
        const FILE = {
            "fileName": data?.files?.myFile.originalFilename,
            "content": contents
        }

        await database.insertOne(FILE)

    } catch(e) {
        console.error(e)
        client.close();
        return res.status(400).json({message: "Uploading failed!"});
    }
    
    client.close();
    return res.status(200).json({ message: 'succ!' })
}

下载客户端

const downloadHandler = async (fileName) => {
    const response = await fetch('/api/download', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({fileName})
    })
    if (response.status !== 200) {
        return
    } else {
        const data = await response.json()
        const linkSource = `data:application/pdf;base64,${data}`
        const a = document.createElement('a')
        const fileName = `${fileName}.pdf`
        a.style.display = 'none'
        a.href = linkSource 
        a.download = fileName
        document.body.appendChild(a)
        a.click()
        document.body.removeChild(a)
    }
}

和服务器下载:

import { NextApiRequest, NextApiResponse } from "next/types";
import { connectToDatabase } from "../../../../database/database";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    if (req.method !== 'POST') {
        return res.status(400).json({message: 'Bad request'});
    }

    const { fileName } = req.body

    const client = await connectToDatabase();
    const database = client.db("Test").collection("Files");

    const result = await database.findOne({ fileName: `${fileName}.pdf` }, { projection: {_id: 0} } );

    if (!result) {
        client.close();
        return res.status(400).json({message: "File not found!"});
    } 

    client.close();
    return res.status(200).setHeader('Content-Type', 'application/pdf').setHeader("Content-Disposition", "attachment; filename=" + result.fileName).send(result.content);

}

正如在KJ的评论中提到的,问题是编码-所以现在是pdf存储在base64和发送回和第四

相关问题