我最近一直在使用 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 上其他人建议的方法,但没有一个对我有用。接下来我可以尝试什么?
vercel.json 应该类似于
{
"rewrites": [
{
"source": "/invoice/:path*",
"destination": "https://invoice-generator-1-yyv7.onrender.com/api/v1/:path*"
}
]
}
获取