为什么服务器端更改没有反映在我的应用程序中?

Why aren't server-side changes being reflected in my app?

我有一个简单的 C# Windows UAP 项目,它使用 HttpClient 在 Web 服务器上调用 PHP 脚本。脚本 return 是一个包含一些 GUID 的 XML 文档(*.xml 省略扩展名的文件,留下一个 GUID)。然后我的应用程序使用该数据。如果我在服务器上进行更改,巧合地导致 PHP 脚本使用 return 不同的数据,我的应用程序仍然使用旧数据(确切地说,它会这样做,直到应用程序重新启动)。如果使用浏览器调用脚本,数据会按照我的预期显示,但应用程序不会对数据执行应有的操作。似乎第一个响应正在被缓存。

这是一个例子:
假设我从文件夹中的一个文件开始,我的 PHP 脚本在其中找到所有 *.xml 文件(在本例中为 eef8401a-b5cd-4da7-ad36-0fb7a8fa6c62.xml)。 该脚本应该并且确实 return:

<?xml version="1.0"?>
<eventlist>
<id>eef8401a-b5cd-4da7-ad36-0fb7a8fa6c62</id>
</eventlist>

当我运行应用程序时,它的反应是一样的。 到目前为止,一切正常。
但是,假设我在文件夹中添加了一个新的 XML 文件(现在是 eee8401a-b5cd-4da7-ad36-0fb7a8fa6c62.xmleef8401a-b5cd-4da7-ad36-0fb7a8fa6c62.xml)。脚本 return 就像我期望的那样:

<?xml version="1.0"?>
<eventlist>
<id>eee8401a-b5cd-4da7-ad36-0fb7a8fa6c62</id>
<id>eef8401a-b5cd-4da7-ad36-0fb7a8fa6c62</id>
</eventlist>

本次应用的响应还是之前的(只有一个id元素)。 这一直持续到应用程序重新启动。在那之后,它会像它应该的那样工作——直到我在文件夹中进行另一个更改。

这是我的 PHP 脚本:

<?php
    header('Content-type: text/xml');
    $handler = opendir('C:\path\to\folder\');
    $ids = '';
    while (($file = readdir($handler)) !== FALSE) {
        if (strpos($file, '.xml') !== FALSE) {
            $ids .= '<id>'.str_replace('.xml', '', $file).'</id>';
        }
    }
    closedir($handler);
    exit('<eventlist>'.$ids.'</eventlist>');
?>

我应用的 C# 代码:

    public static async Task<string> ContactServer(ApiMethod m, IProgress<double[]> prog, params KeyValuePair<string, string>[] args) {
        using (var client = new HttpClient()) {
            var path = m.ToString().ToLower() + "/"; // in this case, is 'list/'.
            //...
            // other stuff, omitted for simplicity
            //...
            var fullUrl = "http://example.com/path/to/api/" + path; // in this case, is 'http://example.com/path/to/api/list/'.
            var d = await client.GetAsync(new Uri(fullUrl));
            var data = await d.Content.ReadAsStringAsync();
            Debug.WriteLine(data);
            return data;
        }
    }

同样,我的 PHP 脚本运行良好,但我的应用得到的响应与我在浏览器中手动 运行 脚本时得到的响应不同。
为什么会这样?

Windows 提供 HTTPClient 的运行时有一个非常积极的网络缓存策略来节省用户的带宽。除非您的服务器明确设置了缓存持续时间 header,否则它会 return 直接从缓存中使用相同 URI 的所有**请求,甚至无需联系您的服务器。

您可以通过以下方式关闭此行为:

设置缓存持续时间header(cache-control:no-cache,等等)。

var request = (HttpWebRequest)WebRequest.Create(url.ToString());
if (request.Headers == null)
    request.Headers = new WebHeaderCollection();
request.Headers.Add("Cache-Control", "no-cache");

正在将随机数添加到您的请求查询字符串中。

string uri = "http://host.com/path?cache=" + Guid.NewGuid().ToString();

或者,正如 CodeCaster 所建议的,您也可以使用 If-Modified-Since header

来避免缓存
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
if (request.Headers == null)
    request.Headers = new WebHeaderCollection();
// Make sure that you format time string according RFC.
request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.UtcNow.ToString("r");

或者您可以添加到客户使用

发出的每个请求中
httpClient.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow.ToString("r");

使用Windows.Web.Http你也可以使用

var httpFilter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
httpFilter.CacheControl.ReadBehavior = 
    Windows.Web.Http.Filters.HttpCacheReadBehavior.MostRecent;
var httpClient = new Windows.Web.Http.HttpClient(httpFilter);

** 我说了所有的要求,但我不知道这是否严格正确,我会看一下并检查并更新这里,虽然 CodeCaster 已经建议 GETHEAD 只要;我肯定在 GET 上看到过,不确定其他人是否在我的脑海中