AWS存储桶可以在特定路由上显示PDF文件

发布于 2025-02-11 19:28:20 字数 4291 浏览 2 评论 0原文

我的NextJS应用程序( v12.1.3 )允许用户上传文件。服务器将它们存储在AWS S3存储桶中。

我以这种方式存储它们:

import _ from 'lodash';
import AWS from 'aws-sdk';
import { v4 as uuidv4 } from 'uuid';
import { config } from '../config';
// file is in base64 format
const uploadFileToS3 = async (file: string) => {
  const s3 = new AWS.S3({
    accessKeyId: config.AWS_ACCESS_KEY_ID,
    secretAccessKey: config.AWS_SECRET_ACCESS_KEY,
    signatureVersion: 'v4',
    region: 'eu-south-1',
  });

  const contentType = file.split(':')[1].split(';')[0];

  const params = {
    Key: uuidv4(),
    Body: Buffer.from(file.replace(/^data:.+;base64,/, ''), 'base64'),
    Bucket: config.AWS_S3_BUCKET_NAME,
    ContentType: contentType,
  };

  return await s3.upload(params).promise();
};

export default uploadFileToS3;

我的存储桶设置:

  • 阻止公共访问(存储桶设置) - > OFF

  • 存储策略

      {
      “版本”:“ 2012-10-17”,
      “陈述”: [
          {
              “ sid”:“ publicReadgetObject”,
              “效果”:“允许”,
              “主要的”: ”*”,
              “动作”:“ s3:getObject”,
              “资源”:“ Arn:AWS:S3 ::: My-Test-Bucket/*”
          }
      这是给出的
    }
     
  • 交叉原始资源共享(CORS)

      [
      {
          “允许的人”:[],
          “允许的方法”:[
              “得到”
          ],,
          “允许的人”:[
              “*”
          ],,
          “ ExposeHeaders”:[]
      }
    这是给出的
     

uploadfiletos3方法返回的URL。

客户端相反,我使用此URL查看图像和PDF文件。 问题 是在某个路由上/generic-entity/{id}我无法预览.pdf文件(没有问题.jpeg或.png文件)。

我遇到了这个错误(甚至是警告):

Cross-Origin Read Blocking (CORB) blocked cross-origin response https://xxxxxx.execute-api.us-east-2.amazonaws.com/default/xxxxxx with MIME type application/pdf. See https://www.chromestatus.com/feature/5629709824032768 for more details.

我环顾四周,发现这是一个新的Web平台安全功能,可帮助减轻侧通道攻击的威胁

在路由上/generic-entity我可以预览PDF文件。不同之处在于,在最后一个上,有一个自动进入AWS:

curl 'https://my-test-bucket.s3.eu-south-1.amazonaws.com/e751b456-c996-4747-bcef-03021cd80357__foo__Doc%2520base.pdf' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en,en-US;q=0.9,it-IT;q=0.8,it;q=0.7' \
  -H 'Connection: keep-alive' \
  -H 'If-Modified-Since: Sun, 26 Jun 2022 19:21:16 GMT' \
  -H 'If-None-Match: "9b1027ca72e993b2607ba5b54e735c64"' \
  -H 'Origin: http://localhost:3000' \
  -H 'Referer: http://localhost:3000/' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: cross-site' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: ".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  --compressed

另一个是没有一个。我试图手动做,但没有解决问题。

有关主要详细信息,这是我用来预览PDF文件的React组件:

// import default react-pdf entry
import { Document, Page, pdfjs } from 'react-pdf';
// import pdf worker as a url, see `next.config.js` and `pdf-worker.js`
import workerSrc from '../../pdf-worker';

pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;

interface Props {
  file: any;
  className?: string;
}
//in this case file is a url.
const PDFPreview: React.FC<Props> = ({ file, className }) => {
  function onDocumentLoadSuccess() {
    document
      .getElementById('react-pdf__Page__canvas')
      ?.style.setProperty('display', 'flex', 'important');
  }

  return (
    <div
      className={`flex overflow-y-hidden rounded-lg cursor-pointer ${className}`}
    >
      <Document file={file} onLoadSuccess={onDocumentLoadSuccess}>
        <Page
          key={`page_${1}`}
          pageNumber={1}
          renderAnnotationLayer={false}
          renderTextLayer={false}
          className="flex w-full"
          style={{ display: 'flex' }}
        />
      </Document>
    </div>
  );
};

export default PDFPreview;

您对如何解决此问题有任何建议吗?

ps i也在 vercel 。您可以在路由/my-entity上看到它有效,而在路由/my-entity/1不使用相同的URL和相同的React组件

My nextjs app (v12.1.3) allows users to upload files. The server stores them in an AWS s3 bucket.

I store them in this way:

import _ from 'lodash';
import AWS from 'aws-sdk';
import { v4 as uuidv4 } from 'uuid';
import { config } from '../config';
// file is in base64 format
const uploadFileToS3 = async (file: string) => {
  const s3 = new AWS.S3({
    accessKeyId: config.AWS_ACCESS_KEY_ID,
    secretAccessKey: config.AWS_SECRET_ACCESS_KEY,
    signatureVersion: 'v4',
    region: 'eu-south-1',
  });

  const contentType = file.split(':')[1].split(';')[0];

  const params = {
    Key: uuidv4(),
    Body: Buffer.from(file.replace(/^data:.+;base64,/, ''), 'base64'),
    Bucket: config.AWS_S3_BUCKET_NAME,
    ContentType: contentType,
  };

  return await s3.upload(params).promise();
};

export default uploadFileToS3;

My bucket settings:

  • Block public access (bucket settings) -> OFF

  • Bucket policy

    {
      "Version": "2012-10-17",
      "Statement": [
          {
              "Sid": "PublicReadGetObject",
              "Effect": "Allow",
              "Principal": "*",
              "Action": "s3:GetObject",
              "Resource": "arn:aws:s3:::my-test-bucket/*"
          }
      ]
    }
    
  • Cross-origin resource sharing (CORS)

    [
      {
          "AllowedHeaders": [],
          "AllowedMethods": [
              "GET"
          ],
          "AllowedOrigins": [
              "*"
          ],
          "ExposeHeaders": []
      }
    ]
    

I store in my mongo DB the url returned from uploadFileToS3 method.

Client side, instead, I use this url to view images and pdf files. The problem is that on a certain route /generic-entity/{id} I cannot preview the .pdf files (there is no problems with .jpeg or .png files).

I get this error (even it is a warning):

Cross-Origin Read Blocking (CORB) blocked cross-origin response https://xxxxxx.execute-api.us-east-2.amazonaws.com/default/xxxxxx with MIME type application/pdf. See https://www.chromestatus.com/feature/5629709824032768 for more details.

and I looked around and found out it is a new web platform security feature that helps mitigate the threat of side-channel attacks

Instead on the route /generic-entity I can preview the pdf files. The difference is that on this last one there is a automatic GET to the aws like this one:

curl 'https://my-test-bucket.s3.eu-south-1.amazonaws.com/e751b456-c996-4747-bcef-03021cd80357__foo__Doc%2520base.pdf' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en,en-US;q=0.9,it-IT;q=0.8,it;q=0.7' \
  -H 'Connection: keep-alive' \
  -H 'If-Modified-Since: Sun, 26 Jun 2022 19:21:16 GMT' \
  -H 'If-None-Match: "9b1027ca72e993b2607ba5b54e735c64"' \
  -H 'Origin: http://localhost:3000' \
  -H 'Referer: http://localhost:3000/' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: cross-site' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: ".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  --compressed

on the other one instead there's is none. I tried to do it manually but it didn't solve the problem.

For major details here's the react component I use to preview the pdf file:

// import default react-pdf entry
import { Document, Page, pdfjs } from 'react-pdf';
// import pdf worker as a url, see `next.config.js` and `pdf-worker.js`
import workerSrc from '../../pdf-worker';

pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;

interface Props {
  file: any;
  className?: string;
}
//in this case file is a url.
const PDFPreview: React.FC<Props> = ({ file, className }) => {
  function onDocumentLoadSuccess() {
    document
      .getElementById('react-pdf__Page__canvas')
      ?.style.setProperty('display', 'flex', 'important');
  }

  return (
    <div
      className={`flex overflow-y-hidden rounded-lg cursor-pointer ${className}`}
    >
      <Document file={file} onLoadSuccess={onDocumentLoadSuccess}>
        <Page
          key={`page_${1}`}
          pageNumber={1}
          renderAnnotationLayer={false}
          renderTextLayer={false}
          className="flex w-full"
          style={{ display: 'flex' }}
        />
      </Document>
    </div>
  );
};

export default PDFPreview;

Do you have any suggestion on how to fix this?

P.S. I also replicated this error in this github repo and I deployed it on vercel. You can see that on the route /my-entity it works, while on the route /my-entity/1 doesn't using the same url and the same react component

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文