简体   繁体   English

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

[英]Why is download hanging in Chrome when serving PDF from Google Cloud Storage via an Express App in Firebase?

I have created an express app to serve PDF files stored in Google cloud storage to the client我创建了一个快速应用程序来向客户端提供存储在 Google 云存储中的 PDF 文件

When hitting the endpoint for a file, the download hangs intermittently in Chrome at a random number of KB downloaded, usually somewhere in the range of 1000KB to 1300 KB.当点击文件的端点时,下载会在 Chrome 中以随机下载的 KB 数间歇性挂起,通常在 1000 KB 到 1300 KB 的范围内。 But I can usually successfully download the file in Firefox, Safari, and Postman.但我通常可以成功下载 Firefox、Safari 和 Postman 中的文件。

下载网络故障

I also noticed that if I omit the 'Content-Disposition' header which forces the browser to try and render the PDF, the browser begins to render it in Chrome but hangs at some random percentage of loading.我还注意到,如果我省略“Content-Disposition”header,它会强制浏览器尝试渲染 PDF,浏览器会开始在 Chrome 中渲染它,但会在加载的某个随机百分比下挂起。 In Firefox/Safari, it will hang at a random percent the first time loading, but usually will render upon an immediate refresh of the URL.在 Firefox/Safari 中,它会在第一次加载时以随机百分比挂起,但通常会在立即刷新 URL 时呈现。

I'm not sure if I'm using streams/buffers incorrectly or if I'm returning the buffer received from Google Storage incorrectly.我不确定我是否错误地使用了流/缓冲区,或者我是否错误地返回了从 Google 存储接收到的缓冲区。 I've been googling this for hours now and am running out of ideas and would appreciate any help anyone has.我已经在谷歌上搜索了好几个小时了,我的想法已经用完了,如果有人能提供任何帮助,我将不胜感激。

Is there a better way to serve the file or do I need to download the file differently from google cloud storage?有没有更好的方法来提供文件,或者我需要以不同于谷歌云存储的方式下载文件?

Thank you for looking at this!谢谢你看这个!

// 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;

Finally figured this out... seems I should have been using the streams directly and piping it into the Express response.终于想通了......似乎我应该直接使用流并将其管道传输到 Express 响应中。

This fixed it for me这为我解决了

// 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))

// ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用Node.js调整Google Cloud Storage中的图像大小并为其提供服务? - Resizing and Serving Images from Google Cloud Storage with Nodejs? 如何从谷歌云存储下载文件? - How to download file from Google Cloud Storage? Firebase 云函数服务本地文件以供下载 - Firebase Cloud Function Serving Local File for Download 通过http下载并使用Node.js流传输到Google Cloud存储 - Download via http and streaming upload to Google Cloud storage using nodejs 如何将映像从Expressjs更新到Google Cloud Storage / Firebase Storage - How update an image from Expressjs to Google Cloud Storage / Firebase Storage 使用下载 url 和 Cloud Functions 从 Firebase 存储中删除文件 - Delete a file from firebase storage using download url with Cloud Functions 将音频文件从Google云端存储流式传输到iOS Firebase客户端应用 - Stream audio file from Google Cloud Storage to iOS Firebase client app 从Google云端存储中流式下载图像时如何正确设置响应标头 - How to properly set response headers when streaming download of an image from Google Cloud Storage 从 Firebase 存储下载 - Download from Firebase Storage 快速缓存来自Google Cloud Storage的图像流 - Express caching Image stream from Google Cloud Storage
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM