错误:对 XMLHttpRequest 的访问已被 CORS 策略阻止:请求的资源上不存在“Access-Control-Allow-Origin”标头

问题描述 投票:0回答:1

我最近一直在使用 MERN Stack 和 TypeScript 开发在线发票生成器。我添加了一个选项,可以在单击按钮时使用 Puppeteer 库生成 PDF。此功能在我的本地设备上运行良好。我已将这个项目的后端部署在 Render 上,将前端部署在 Vercel 上。但是,当我在部署的页面上点击按钮生成PDF时,出现以下错误:

Access to XMLHttpRequest at 'https://invoice-generator-1-yyv7.onrender.com/api/v1/generate-pdf' from origin 'https://invoice-ninja-aryan.vercel.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这是我的心:

app.use(
    cors({
        origin: "*",
        credentials: true,
        methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
    })
);

下面是实现generatePDF函数的后端函数

app.post('/api/v1/generate-pdf', auth, async (req, res) => {
    const { user, products} = req.body;

    let totalRate = 0;
    const processedProducts = products.map(product => {
        const total = product.quantity * product.price;
        totalRate += total;
        return {
            ...product,
            total: total
        };
    });

    // Calculate total GST and grand total
    const totalGST = totalRate * 0.18; // Assuming GST rate is 18%
    const grandTotal = totalRate + totalGST;

    // Load HTML template
    const templatePath = path.join(__dirname, 'invoiceTemplate.html');
    const templateHtml = fs.readFileSync(templatePath, 'utf8');

    // Compile template with Handlebars
    const template = Handlebars.compile(templateHtml);
    const html = template({
        userName: user.name,
        userEmail: user.email,
        products: processedProducts,
        totalRate: totalRate,
        totalGST: totalGST,
        grandTotal: grandTotal
    });
    // Launch Puppeteer and generate PDF
    const browser = await puppeteer.launch({
        headless: true,
        devtools: true,
        args: [
            '--disable-web-security',
            '--disable-features=IsolateOrigins',
            '--disable-site-isolation-trials',
            '--disable-features=BlockInsecurePrivateNetworkRequests'
        ]
    });
    const page = await browser.newPage();
    await page.setContent(html);
    const pdfBuffer = await page.pdf({ 
        path: 'mypdf.pdf',
        format: 'A4',
        printBackground: true,
    });
    await browser.close();

    // Send PDF as response
    res.set({
        'Content-Type': 'application/pdf',
        'Content-Length': pdfBuffer.length
    });
    res.send(pdfBuffer);
});

以下是 Express 设置和 CORS 中间件:

const express = require("express");
const app = express();
const cors = require("cors");

app.use(express.json());
app.use(cookieParser());

app.use(
    cors({
        origin: "*",
        credentials: true,
        methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
    })
);

app.use((req, res, next) => {
    res.setHeader(
      "Access-Control-Allow-Origin",
      "*"
    );
    res.setHeader(
      "Access-Control-Allow-Methods",
      "GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS,CONNECT,TRACE"
    );
    res.setHeader(
      "Access-Control-Allow-Headers",
      "Content-Type, Authorization, X-Content-Type-Options, Accept, X-Requested-With, Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
    );
    res.setHeader("Access-Control-Allow-Credentials", true);
    res.setHeader("Access-Control-Allow-Private-Network", true);
    //  Firefox caps this at 24 hours (86400 seconds). Chromium (starting in v76) caps at 2 hours (7200 seconds). The default value is 5 seconds.
    res.setHeader("Access-Control-Max-Age", 7200);
  
    next();
  });

我尝试了 Stack Overflow 上其他人建议的方法,但没有一个对我有用。接下来我可以尝试什么?

node.js express cors xmlhttprequest puppeteer
1个回答
0
投票

vercel.json 应该类似于

{
  "rewrites": [
    {
      "source": "/invoice/:path*",
      "destination": "https://invoice-generator-1-yyv7.onrender.com/api/v1/:path*"
    }
  ]
}

然后您从 https://myapp.vercel.app/invoice/generate_pdf

获取
© www.soinside.com 2019 - 2024. All rights reserved.