最近有人反馈说,通过Feedly订阅我的博客总是失败。我自己在浏览器里打开`wuqishi.com/feed/`明明一切正常,这典型的“RSS 403”问题,相当于关上了订阅的大门。折腾一圈下来,发现根源无非两个:**服务器上的PHP乱输出**,或者**Cloudflare等CDN的“误杀”** 。下面就把我的排查过程和解决方案贴出来,希望能帮你一把。  首先,我们得知道问题出在哪个环节。打开终端,用下面这条命令模拟一下RSS阅读器的请求: ```bash curl -I -H "User-Agent: Feedly/1.0" https://wuqishi.com/feed/ ``` 重点看返回的HTTP状态码和响应头: - **如果状态码是403,并且响应头里带有** **`CF-RAY`****字段**:那问题八成出在Cloudflare的WAF或者Bot防护规则上,你的请求在CDN边缘就被掐掉了。直接看下面关于Cloudflare的章节。 - **如果状态码不是200,也没有** **`CF-RAY`****头**:这是你的源站服务器(比如Nginx/PHP)自己返回的错误,去看PHP修复那部分。 - **如果返回了XML,但内容最前面混入了PHP的Warning或Deprecated信息**:这就是经典的“PHP输出污染”,XML格式被破坏,阅读器自然无法识别。解决方案也在PHP部分。 ## PHP层修复:搞定版本兼容性与错误输出 不同PHP版本,坑点不一样。这里我简单列一下,方便大家对号入座: - **PHP 7.4 / 8.0 / 8.1**:这几个版本比较安分,主要确保`php.ini`里`display_errors = Off`别让警告输出就行。不过PHP 7.4已经停止官方支持了,能升级还是建议升级。 - **PHP 8.2**:**重点关注!** 这个版本开始默认弃用“动态属性”,很多老程序会因此抛出`Deprecated`警告,这些警告会直接插在RSS的XML开头,导致解析失败。解决办法是在程序入口或`php.ini`里关掉错误显示。 - **PHP 8.3 / 8.4**:类型系统越来越严格。8.3对动态属性控制更狠,8.4则弃用了隐式可空类型声明。确保你用的博客程序(如Typecho, WordPress)已经发布了兼容这些新版本的更新。 **具体操作**: 在你的网站入口文件(例如`index.php`)最开头,或者直接在`php.ini`配置文件中,加入以下代码来压制错误输出: ```ini // 方法一:在程序入口文件(如 index.php)顶部添加 error_reporting(0); ini_set('display_errors', '0'); // 方法二:修改 php.ini(效果更全局) display_errors = Off error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED ``` **我的建议是,无论用哪个版本,在生产环境永远关闭** **`display_errors`** **。** 修改完配置后,**别忘了重启PHP-FPM服务**(例如 `systemctl restart php8.2-fpm`)。 ## Cloudflare层修复:让WAF规则放行你的订阅源 浏览器能打开,阅读器报403——这是Cloudflare把RSS阅读器的请求当成可疑机器人给拦了。我们需要调整它的安全规则。 ### 第一步:关闭“Bot Fight Mode” **操作路径**:Cloudflare 控制台 → 安全性 (Security) → 自动程序 (Bots) 找到“自动程序攻击模式”(Bot Fight Mode),**把它关掉**。免费版的这个模式有点“宁杀错不放过”,会误伤很多正常的自动请求,比如RSS阅读器、搜索引擎爬虫。 如果你是Pro版用户,可以开启更智能的“Super Bot Fight Mode”,然后在“已验证的机器人”(Verified Bots)分类中,设置规则为“允许”(Allow),这样Feedly、Googlebot这些正规军就能通行了。 ### 第二步:配置精准的WAF规则 我们需要创建一条规则,专门放行RSS订阅地址的请求,不让后续的安防规则拦截它。 在Cloudflare控制台,进入**安全性 → WAF → 自定义规则**,创建一个新规则: 1. **规则名称**:比如“Allow RSS Feed Subscribers” 2. **规则表达式 (When incoming requests match…)** : ```ini (http.request.uri.path contains "/feed") or (http.request.uri.path contains "/rss") or (http.request.uri.path contains "/atom") ``` (请根据你博客实际的RSS路径修改) 3. **操作 (Then…)** :选择 **跳过 (Skip)** 4. **在Skip的子选项中,勾选“跳过所有剩余的自定义规则”(Skip remaining custom rules)** 。这一步非常关键,确保RSS请求不受其他可能存在的拦截规则影响。 然后,把这个规则的**优先级拖到比较靠前的位置**,确保它先于其他可能的拦截规则生效。 ### 第三步:清除缓存 修改完任何Cloudflare设置后,一个好习惯是清除缓存。 **操作路径**:Cloudflare 控制台 → 缓存 (Caching) → 配置 (Configuration) → 清除所有内容 (Purge Everything)。 点“清除所有”。之后,再用阅读器或`curl`命令测试一下你的RSS地址,应该就能正常返回了。 ## 源站加固:Nginx配置兜底 为了防止有人绕过Cloudflare直接攻击源站,或者作为你没用CDN时的防护,可以在Nginx里加一层基础防护。 把下面这段配置加到你的网站Nginx配置文件中(通常是 `server`块内): ```nginx location ~ ^/(feed|rss|atom) { # 只允许GET请求访问RSS limit_except GET { deny all; } # 拦截一些常见的恶意扫描工具的UA if ($http_user_agent ~* (sqlmap|nikto|nmap|zgrab|gobuster)) { return 444; } # 设置访问频率限制,防止被刷 limit_req zone=one burst=5 nodelay; # 这里是你的原始PHP处理逻辑,保持不变 try_files $uri $uri/ /index.php?$args; } # 可以顺便拦一下其他常见恶意请求路径 location ~* /(wp-admin|xmlrpc\.php|\.env|\.git) { return 444; } ``` 记得根据你服务器的实际情况,调整频率限制区域(`zone`)的名称和`limit_req`的参数。配置好后,运行 `nginx -t`测试配置,然后 `systemctl reload nginx`重载生效。 ## 验证清单 都配置完之后,可以用下面这个清单快速检查一下是否全部生效: 1. **检查PHP输出**:直接用浏览器打开你的RSS订阅地址,查看网页源代码,看最前面有没有不该出现的PHP错误信息。 2. **模拟阅读器请求**:在终端运行 `curl -H "User-Agent: Feedly/1.0" https://你的域名.com/feed`,确认返回状态码是200,并且内容是干净的XML。 3. **清理Cloudflare缓存**:在Cloudflare控制台的“缓存”设置里,执行“清除所有”的操作,确保新规则立即生效。 4. **终极验证**:去 [W3C Feed验证服务](https://validator.w3.org/feed/)或你的Feedly订阅器里,重新添加一遍订阅链接,看看是否成功。 按照上面步骤走一遍,绝大多数RSS 403的问题都能解决。如果还有问题,欢迎在评论区留言讨论。 Loading... 最近有人反馈说,通过Feedly订阅我的博客总是失败。我自己在浏览器里打开`wuqishi.com/feed/`明明一切正常,这典型的“RSS 403”问题,相当于关上了订阅的大门。折腾一圈下来,发现根源无非两个:**服务器上的PHP乱输出**,或者**Cloudflare等CDN的“误杀”** 。下面就把我的排查过程和解决方案贴出来,希望能帮你一把。  首先,我们得知道问题出在哪个环节。打开终端,用下面这条命令模拟一下RSS阅读器的请求: ```bash curl -I -H "User-Agent: Feedly/1.0" https://wuqishi.com/feed/ ``` 重点看返回的HTTP状态码和响应头: - **如果状态码是403,并且响应头里带有** **`CF-RAY`****字段**:那问题八成出在Cloudflare的WAF或者Bot防护规则上,你的请求在CDN边缘就被掐掉了。直接看下面关于Cloudflare的章节。 - **如果状态码不是200,也没有** **`CF-RAY`****头**:这是你的源站服务器(比如Nginx/PHP)自己返回的错误,去看PHP修复那部分。 - **如果返回了XML,但内容最前面混入了PHP的Warning或Deprecated信息**:这就是经典的“PHP输出污染”,XML格式被破坏,阅读器自然无法识别。解决方案也在PHP部分。 ## PHP层修复:搞定版本兼容性与错误输出 不同PHP版本,坑点不一样。这里我简单列一下,方便大家对号入座: - **PHP 7.4 / 8.0 / 8.1**:这几个版本比较安分,主要确保`php.ini`里`display_errors = Off`别让警告输出就行。不过PHP 7.4已经停止官方支持了,能升级还是建议升级。 - **PHP 8.2**:**重点关注!** 这个版本开始默认弃用“动态属性”,很多老程序会因此抛出`Deprecated`警告,这些警告会直接插在RSS的XML开头,导致解析失败。解决办法是在程序入口或`php.ini`里关掉错误显示。 - **PHP 8.3 / 8.4**:类型系统越来越严格。8.3对动态属性控制更狠,8.4则弃用了隐式可空类型声明。确保你用的博客程序(如Typecho, WordPress)已经发布了兼容这些新版本的更新。 **具体操作**: 在你的网站入口文件(例如`index.php`)最开头,或者直接在`php.ini`配置文件中,加入以下代码来压制错误输出: ```ini // 方法一:在程序入口文件(如 index.php)顶部添加 error_reporting(0); ini_set('display_errors', '0'); // 方法二:修改 php.ini(效果更全局) display_errors = Off error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED ``` **我的建议是,无论用哪个版本,在生产环境永远关闭** **`display_errors`** **。** 修改完配置后,**别忘了重启PHP-FPM服务**(例如 `systemctl restart php8.2-fpm`)。 ## Cloudflare层修复:让WAF规则放行你的订阅源 浏览器能打开,阅读器报403——这是Cloudflare把RSS阅读器的请求当成可疑机器人给拦了。我们需要调整它的安全规则。 ### 第一步:关闭“Bot Fight Mode” **操作路径**:Cloudflare 控制台 → 安全性 (Security) → 自动程序 (Bots) 找到“自动程序攻击模式”(Bot Fight Mode),**把它关掉**。免费版的这个模式有点“宁杀错不放过”,会误伤很多正常的自动请求,比如RSS阅读器、搜索引擎爬虫。 如果你是Pro版用户,可以开启更智能的“Super Bot Fight Mode”,然后在“已验证的机器人”(Verified Bots)分类中,设置规则为“允许”(Allow),这样Feedly、Googlebot这些正规军就能通行了。 ### 第二步:配置精准的WAF规则 我们需要创建一条规则,专门放行RSS订阅地址的请求,不让后续的安防规则拦截它。 在Cloudflare控制台,进入**安全性 → WAF → 自定义规则**,创建一个新规则: 1. **规则名称**:比如“Allow RSS Feed Subscribers” 2. **规则表达式 (When incoming requests match…)** : ```ini (http.request.uri.path contains "/feed") or (http.request.uri.path contains "/rss") or (http.request.uri.path contains "/atom") ``` (请根据你博客实际的RSS路径修改) 3. **操作 (Then…)** :选择 **跳过 (Skip)** 4. **在Skip的子选项中,勾选“跳过所有剩余的自定义规则”(Skip remaining custom rules)** 。这一步非常关键,确保RSS请求不受其他可能存在的拦截规则影响。 然后,把这个规则的**优先级拖到比较靠前的位置**,确保它先于其他可能的拦截规则生效。 ### 第三步:清除缓存 修改完任何Cloudflare设置后,一个好习惯是清除缓存。 **操作路径**:Cloudflare 控制台 → 缓存 (Caching) → 配置 (Configuration) → 清除所有内容 (Purge Everything)。 点“清除所有”。之后,再用阅读器或`curl`命令测试一下你的RSS地址,应该就能正常返回了。 ## 源站加固:Nginx配置兜底 为了防止有人绕过Cloudflare直接攻击源站,或者作为你没用CDN时的防护,可以在Nginx里加一层基础防护。 把下面这段配置加到你的网站Nginx配置文件中(通常是 `server`块内): ```nginx location ~ ^/(feed|rss|atom) { # 只允许GET请求访问RSS limit_except GET { deny all; } # 拦截一些常见的恶意扫描工具的UA if ($http_user_agent ~* (sqlmap|nikto|nmap|zgrab|gobuster)) { return 444; } # 设置访问频率限制,防止被刷 limit_req zone=one burst=5 nodelay; # 这里是你的原始PHP处理逻辑,保持不变 try_files $uri $uri/ /index.php?$args; } # 可以顺便拦一下其他常见恶意请求路径 location ~* /(wp-admin|xmlrpc\.php|\.env|\.git) { return 444; } ``` 记得根据你服务器的实际情况,调整频率限制区域(`zone`)的名称和`limit_req`的参数。配置好后,运行 `nginx -t`测试配置,然后 `systemctl reload nginx`重载生效。 ## 验证清单 都配置完之后,可以用下面这个清单快速检查一下是否全部生效: 1. **检查PHP输出**:直接用浏览器打开你的RSS订阅地址,查看网页源代码,看最前面有没有不该出现的PHP错误信息。 2. **模拟阅读器请求**:在终端运行 `curl -H "User-Agent: Feedly/1.0" https://你的域名.com/feed`,确认返回状态码是200,并且内容是干净的XML。 3. **清理Cloudflare缓存**:在Cloudflare控制台的“缓存”设置里,执行“清除所有”的操作,确保新规则立即生效。 4. **终极验证**:去 [W3C Feed验证服务](https://validator.w3.org/feed/)或你的Feedly订阅器里,重新添加一遍订阅链接,看看是否成功。 按照上面步骤走一遍,绝大多数RSS 403的问题都能解决。如果还有问题,欢迎在评论区留言讨论。 Last modification:April 1, 2026 © Allow specification reprint Support Appreciate the author AliPayWeChat Like 如果觉得我的文章对你有用,请随意赞赏
4 comments
干活啊,虽然现在没碰到,先收藏,万一碰到有用。
专业
又涨见识了
刚好自己遇到这个问题了