Ajax RSS与OpenWeatherMap缓存问题:GET改POST实现实时刷新咨询
Hey there! Let's break down why your RSS feeds and OpenWeatherMap API calls aren't refreshing in real-time, and how to fix it without switching to POST requests.
问题根源分析
你怀疑的浏览器缓存和GET请求机制确实是关键,但GET本身不是问题——真正的问题在于缓存策略以及你当前实现中nocache参数的生成逻辑有漏洞。目前你的nocache变量只在页面加载时生成一次,后续所有请求都会带上同一个随机值,浏览器还是会把它当成相同的请求缓存起来。另外,服务器端和PHP本身也可能缓存远程资源的响应,导致你看到旧内容。
为什么不需要改成POST
POST请求是用于提交数据到服务器的,而获取RSS/天气数据这类操作属于只读资源请求,完全符合GET的语义。强行改成POST不仅违反REST设计规范,还不一定能解决缓存问题——部分浏览器或代理服务器依然可能缓存POST请求的响应。所以我们应该聚焦在缓存控制上,而不是换请求方法。
具体修改方案
1. 前端代码优化
核心是每次发起请求时生成新的nocache值,并添加缓存控制请求头,确保浏览器不会复用缓存的响应:
<script> function showRSS(str) { if (str.length === 0) { document.getElementById("rssOutput").innerHTML = ""; return; } // 每次请求生成新的随机数,确保URL唯一 const nocache = "&nocache=" + Math.random() * 1000000; let xmlhttp; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } // 添加缓存控制请求头,强制浏览器不缓存 xmlhttp.setRequestHeader("Cache-Control", "no-cache, no-store, must-revalidate"); xmlhttp.setRequestHeader("Pragma", "no-cache"); xmlhttp.onreadystatechange = function() { if (this.readyState === 4 && this.status === 200) { document.getElementById("rssOutput").innerHTML = this.responseText; } }; xmlhttp.open("GET", "getrss.php?q=" + str + nocache, true); xmlhttp.send(); } </script>
修改点说明:
- 将
nocache的生成移到showRSS函数内部,确保每次调用都生成新的随机值 - 添加
Cache-Control和Pragma请求头,明确告诉浏览器不要缓存这个请求的响应
2. 后端PHP代码优化
需要在PHP响应中添加禁止缓存的头部,同时确保PHP加载远程RSS时不使用缓存:
<?php // 首先发送禁止缓存的响应头,告诉浏览器和代理不要缓存这个页面 header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1 header("Pragma: no-cache"); // HTTP 1.0 header("Expires: 0"); // 过期时间设为过去,强制浏览器重新请求 // get the q parameter from URL $q = $_GET["q"]; // find out which feed was selected if($q=="Baden-Württemberg") { $xmlUrl = "https://verkehrsmeldungen.polizei-bw.de/TicRss.ashx?region=BW"; } elseif($q=="Bayern") { $xmlUrl = "http://www.br.de/verkehr-static/verkehrsmeldungen-rss.xml"; } // 创建不缓存的流上下文,确保PHP拉取远程XML时获取最新内容 $context = stream_context_create([ 'http' => [ 'header' => "Cache-Control: no-cache, no-store, must-revalidate\r\n" . "Pragma: no-cache\r\n" ] ]); $xmlDoc = new DOMDocument(); // 使用流上下文加载XML,绕过PHP的远程资源缓存 $xmlDoc->load($xmlUrl, LIBXML_NONET, $context); //get elements from "<channel>" $channel=$xmlDoc->getElementsByTagName('channel')->item(0); $channel_title = $channel->getElementsByTagName('title') ->item(0)->childNodes->item(0)->nodeValue; $channel_link = $channel->getElementsByTagName('link') ->item(0)->childNodes->item(0)->nodeValue; $channel_desc = $channel->getElementsByTagName('description') ->item(0)->childNodes->item(0)->nodeValue; //output elements from "<channel>" echo("<p ><a href='" . $channel_link . "'>" . $channel_title . "</a>"); echo("<br>"); echo($channel_desc . "</p>"); //get and output "<item>" elements $x=$xmlDoc->getElementsByTagName('item'); for ($i=0; $i<=5; $i++) { $item_title=$x->item($i)->getElementsByTagName('title') ->item(0)->childNodes->item(0)->nodeValue; $item_link=$x->item($i)->getElementsByTagName('link') ->item(0)->childNodes->item(0)->nodeValue; $item_desc=$x->item($i)->getElementsByTagName('description') ->item(0)->childNodes->item(0)->nodeValue; echo ("<p ><a href='" . $item_link . "'>" . $item_title . "</a>"); echo ("<br>"); echo ($item_desc . "</p>"); } ?>
修改点说明:
- 添加了三个缓存控制响应头,彻底禁止浏览器和代理缓存PHP输出
- 创建了带缓存控制头的流上下文,让PHP加载远程RSS时直接请求最新内容,而不是复用本地缓存
总结
通过调整前端的nocache生成逻辑和缓存请求头,再配合后端的缓存禁止响应头,就能解决实时刷新的问题,完全不需要切换到POST请求。这些修改既符合HTTP规范,又能确保每次请求都获取到最新的内容。
内容的提问来源于stack exchange,提问作者Dario JJ

