微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么在通过 Firebase 中的 Express 应用程序从 Google Cloud Storage 提供 PDF 时下载在 Chrome 中挂起?

如何解决为什么在通过 Firebase 中的 Express 应用程序从 Google Cloud Storage 提供 PDF 时下载在 Chrome 中挂起?

我创建了一个 express 应用程序来向客户端提供存储在 Google 云存储中的 PDF 文件

当点击文件的端点时,下载在 Chrome 中间歇性地挂起,下载的 KB 数是随机的,通常在 1000 KB 到 1300 KB 的范围内。但是我通常可以在 Firefox、Safari 和 Postman 中成功下载文件

downloading network failures

我还注意到,如果我省略了强制浏览器尝试呈现 PDF 的“Content-disposition”标头,浏览器会开始在 Chrome 中呈现它,但会以某个随机加载百分比挂起。在 Firefox/Safari 中,它会在第一次加载时以随机百分比挂起,但通常会在立即刷新 URL 时呈现。

我不确定我是否错误地使用了流/缓冲区,或者我是否错误地返回了从 Google Storage 收到的缓冲区。我已经在谷歌上搜索了几个小时,但我的想法已经用完了,如果有人提供任何帮助,我将不胜感激。

是否有更好的方式来提供文件,或者我是否需要以不同于谷歌云存储的方式下载文件

感谢您看到这里!

// FileService for fetching from Google Storage
export class FilesService {

    pdfBucket: Bucket

    constructor() {
        this.pdfBucket = admin.storage().bucket(config.firebase_ppe_product_pdfs_bucket)
    }

    getPdfFile(filePath: string) : File {
        return this.pdfBucket.file(filePath);
    }

    async getBufferOfPdfFile(filePath: string) {
        const file = await this.getPdfFile(filePath)

        // Download the file to a buffer
        // Omit the "destination" option from download method to receive a buffer
        const [ buffer ] = await file.download()

        return buffer
    }
}
/* index.ts - main express server */ 

import * as functions from "firebase-functions";
import logger from "morgan";
import cookieParser from "cookie-parser";
import express from "express";
import cors from "cors";

import files from './routers/files'

const app = express();

app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.use('/files',files);

export const server = functions.https.onRequest(app)
/* files.ts - files router for express server */ 

import express,{Express} from "express";
import {FilesService} from "../../services/files";
import logger from "../../services/rollbar";

const router = express.Router();

const filesService = new FilesService()

/* GET pdf */
router.get('/product/:slug',async (req,res) => {
    const slug = req.params.slug

    try {
        // Get the file buffer
        const data = await filesService.getBufferOfPdfFile(slug)

        res.writeHead(200,{
            'Content-Type': 'application/pdf','Content-disposition': `attachment; filename=${slug}`,'Content-Length': data.length
        })
        res.end(data,'binary')
    } catch (err) {
        res.status(500).send("Looks like there was a problem...")
        logger.error(err)
    }
});

export default router;

解决方法

终于想通了...似乎我应该直接使用流并将其通过管道传输到 Express 响应中。

这为我修好了

// in the files.ts express handler
// ...

// Get the file stream
const file = await filesService.getPdfFile(`${hostname}/${slug}`)
const stream = file.createReadStream()

res.on('error',err => logger.error(err))
res.set('Content-Type','application/pdf')

if (download) {
    res.set('Content-Disposition',`attachment; filename=${slug}`)
}

// Pipe file read stream to the response (write stream)
stream.pipe(res)
stream.on('error',err => logger.error(err))

// ...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。