React使用fetch获取Shopify博客Feed失败,如何解决?
我有一套曾成功获取WordPress Feed的代码,但无法在Shopify上实现同样效果。我已在Shopify中创建私有应用,并将访问令牌放入请求头,但React端返回如下CORS错误:
Access to fetch at 'https://example.com/blogs/blog.atom' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
使用的代码如下:
const mediumRssFeed = "https://example.com/blogs/blog.atom"; const MAX_ARTICLES = 99; const [articles, setArticles] = useState(); useEffect(() => { const loadArticles = async () => { fetch(mediumRssFeed, { headers: {"X-Shopify-Access-Token": "XXX", Accept: "application/json" }, crossDomain: true }) .then((res) => res.json()) .then((newArticles) => newArticles.slice(0, MAX_ARTICLES)) .then((articles) => setArticles(articles)) .catch((error) => console.log(error)); }; loadArticles(); }, [MAX_ARTICLES]);
请问如何将Shopify商店的博客集成到React项目中?
核心问题分析
你当前的问题有两个关键矛盾:
- Shopify博客的
.atomFeed是XML格式,不是JSON,直接用res.json()解析会报错 - Shopify的公开Feed接口不支持前端跨域请求,且私有应用令牌不能直接暴露在前端代码中(存在密钥泄露风险)
方法一:后端代理(生产环境推荐)
搭建后端代理接口,由后端发起请求获取Shopify博客数据,再返回给前端,既避开CORS限制,又保护令牌安全。
示例Node.js代理代码(Express框架)
const express = require('express'); const axios = require('axios'); const xml2js = require('xml2js'); const app = express(); // 代理接口 app.get('/api/shopify-blog', async (req, res) => { try { // 从Shopify获取XML格式的博客Feed const feedResponse = await axios.get('https://example.com/blogs/blog.atom', { headers: { 'X-Shopify-Access-Token': '你的私有应用令牌' } }); // 将XML转换为JSON格式 const parser = new xml2js.Parser({ explicitArray: false }); parser.parseString(feedResponse.data, (parseErr, result) => { if (parseErr) throw parseErr; // 提取文章数据并截取指定数量 const articles = result.feed.entry.slice(0, 99); res.json(articles); }); } catch (error) { res.status(500).json({ error: error.message }); } }); app.listen(4000, () => console.log('代理服务运行在 http://localhost:4000'));
React端修改后的请求代码
const proxyUrl = "http://localhost:4000/api/shopify-blog"; const [articles, setArticles] = useState(); useEffect(() => { const loadArticles = async () => { fetch(proxyUrl) .then((res) => res.json()) .then((articles) => setArticles(articles)) .catch((error) => console.log(error)); }; loadArticles(); }, []);
方法二:使用Shopify Storefront API
如果私有应用有权限,可调用Shopify Storefront API直接获取结构化的JSON博客数据,同样通过后端代理发起请求:
后端代理中的Storefront API请求示例
app.get('/api/shopify-blog', async (req, res) => { try { // GraphQL查询语句,按需调整返回字段 const query = ` { blogByHandle(handle: "blog") { articles(first: 99) { edges { node { title excerpt publishedAt url featuredImage { url } } } } } } `; const response = await axios.post('https://example.com/api/2024-07/graphql.json', { query }, { headers: { 'X-Shopify-Storefront-Access-Token': '你的Storefront令牌' } }); // 提取并格式化文章数据 const articles = response.data.data.blogByHandle.articles.edges.map(edge => edge.node); res.json(articles); } catch (error) { res.status(500).json({ error: error.message }); } });
方法三:no-cors模式(仅临时调试)
如果只是临时测试,可设置mode: 'no-cors'绕过CORS,但这种方式只能获取不透明响应,无法解析内容,绝对不推荐生产环境使用:
fetch(mediumRssFeed, { mode: 'no-cors', headers: {"X-Shopify-Access-Token": "XXX"} })
内容的提问来源于stack exchange,提问作者Paul VI

