React网页爬虫遇CORS跨域问题,如何配置通用代理解决?
React网页爬虫的CORS跨域与代理配置问题
我正在开发一款基于React的网页爬虫程序,支持用户输入URL后抓取页面的标题与作者信息,但目前遭遇了CORS跨域限制问题。
我曾针对特定URL配置过代理并生效,但该程序需要适配大量存在CORS限制的URL,例如tistory这类站点(域名前缀为博客名称,后缀为平台域名)。我尝试编写了如下代理配置,但并未生效:
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app){ app.use( createProxyMiddleware('tistory/', { target: 'tistory.com/', pathRewrite: { 'tistory/^':'' }, changeOrigin: true }) ) };
直接请求目标URL的核心代码如下:
//let firstTestURL = "https://blog.naver.com/mayoha/223015532241"; //let testURLonProxy = "naver/siji5000/223015377877"; let testURL = "https://peursen.tistory.com/270"; axios.get(testURL) .then((response) =>{ let body = response.data; const $ = cheerio.load(body); let theURLtitle = $("title").text(); console.log(theURLtitle); }) .catch(err =>{ console.log(err); })
修正代理配置
原配置存在三个核心问题:target缺少协议头、匹配规则无法适配子域名场景、pathRewrite正则写法错误。以下是修正后的配置,支持tistory这类带动态子域名的站点:
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app){ // 处理tistory类站点的代理 app.use( createProxyMiddleware('/tistory/**', { target: 'https://tistory.com', pathRewrite: { '^/tistory/': '' // 移除路径开头的/tistory/前缀 }, changeOrigin: true, // 动态匹配子域名 router: function(req) { // 从请求路径中提取子域名部分,比如peursen const subdomain = req.path.split('/')[2]; return `https://${subdomain}.tistory.com`; } }) ); // 可扩展添加naver博客的代理规则 app.use( createProxyMiddleware('/naver/**', { target: 'https://blog.naver.com', pathRewrite: { '^/naver/': '' }, changeOrigin: true, router: function(req) { const blogId = req.path.split('/')[2]; return `https://blog.naver.com/${blogId}`; } }) ); };
修改后,前端请求需要调整为代理路径,比如原URL https://peursen.tistory.com/270 要改为 /tistory/peursen/270:
// 替换为代理路径 let proxyURL = "/tistory/peursen/270"; axios.get(proxyURL) .then((response) =>{ let body = response.data; const $ = cheerio.load(body); let theURLtitle = $("title").text(); console.log(theURLtitle); }) .catch(err =>{ console.log(err); })
其他可行的跨CORS解决方案
自建后端API中转(推荐生产环境使用)
浏览器的CORS限制仅针对前端请求,后端服务不受此限制。可以搭建一个简单的后端接口,由后端负责抓取目标页面内容,再返回给前端。示例代码如下:
后端(Express):
const express = require('express'); const axios = require('axios'); const cheerio = require('cheerio'); const cors = require('cors'); const app = express(); app.use(cors()); app.use(express.json()); app.get('/fetch-page', async (req, res) => { const targetURL = req.query.url; if (!targetURL) { return res.status(400).json({ error: '缺少目标URL参数' }); } try { const response = await axios.get(targetURL); const $ = cheerio.load(response.data); const title = $("title").text(); // 可扩展提取作者信息,需根据不同站点的DOM结构适配 res.json({ title }); } catch (err) { res.status(500).json({ error: `抓取失败:${err.message}` }); } }); app.listen(3001, () => console.log('后端服务运行在端口3001'));
前端请求:
let testURL = "https://peursen.tistory.com/270"; axios.get('http://localhost:3001/fetch-page', { params: { url: testURL } }) .then((response) =>{ console.log('页面标题:', response.data.title); }) .catch(err =>{ console.log(err); })
开发阶段临时方案:公开CORS代理
开发时可以使用公开的CORS代理服务,但存在数据安全风险,不适合生产环境。使用时只需在目标URL前添加代理前缀即可:
let proxyPrefix = "https://cors-anywhere.herokuapp.com/"; let testURL = proxyPrefix + "https://peursen.tistory.com/270"; axios.get(testURL) // ...后续逻辑不变
内容的提问来源于stack exchange,提问作者jujujamong
相关产品推荐
相关产品推荐

