1

我正在尝试让“if-modified-since”标头与我的 WCF Web 服务一起使用。

当用户向我的服务发出请求时,我将 ETag 添加到包含请求时间戳的传出响应中,如下所示:

var tag = String.Format("\"{0:o}\"", new DateTimeOffset(DateTime.Now));

这将产生以下 ETag 标头:

ETag: "2011-10-27T13:09:39.6242263-04:00"

然后,我将这个值作为 if-modified-since 标头回显给后续请求,如下所示:

If-Modified-Since:2011-10-27T13:09:39.6242263-04:00

当我检查 WebOperationContext.Current.Headers.IfModifiedSince 时,我从来没有得到提供的值。该值固定为“12/31/1969 7:00:00 PM”。

我究竟做错了什么?

更新

我应该补充一点,使用 Fiddler,我可以为 If-Modified-Since 标头设置任何值,并且仍然在代码中获得相同的 1969 值。

4

1 回答 1

2

首先If-Modified-Since是关于资源最后修改时间的ETag条件 GET,而关于资源标识符的条件 GET,请注意混合这两个概念。

在 WCF 服务中实现对 If-Modified-Since 的支持的正确方法是使用在对象中CheckConditionalRetrieve传递DateTimeWebOperationContext.Current.IncomingRequest- 请参阅下面的代码。如果 IMS 标头的值早于您传递给 的日期CheckConditionalRetrieve,则该方法将在该点退出并返回 304(未修改)响应。否则它将继续。下面的代码显示了这一点。

另一个问题:即使您使用的日期格式(ISO 8601)有效,但根据规范(http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html中的第 14.25 节,和http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1中的第 3.3.1 节),因此您应该考虑使用有效的格式来防止将来出现问题。

您可以在http://blogs.msdn.com/b/endpoint/archive/2010/02/25/conditional-get-and-etag-support-in-wcf-webhttp找到一篇关于 WCF 中条件 GET 支持的好帖子-服务.aspx

public class StackOverflow_7919718
{
    [ServiceContract]
    public class Service
    {
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        public string GetData()
        {
            Console.WriteLine("If-Modified-Since header (1): {0}", WebOperationContext.Current.IncomingRequest.IfModifiedSince);
            WebOperationContext.Current.IncomingRequest.CheckConditionalRetrieve(DateTime.UtcNow);
            return "Data";
        }
    }

    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
        host.Open();
        Console.WriteLine("Host opened");

        Console.WriteLine("Not sending If-Modified-Since header (should return 200):");
        Util.SendRequest(baseAddress + "/GetData", "GET", null, null);

        Console.WriteLine("Sending data in the past, ISO 8601 format (should return 200):");
        Util.SendRequest(baseAddress + "/GetData", "GET", null, null,
            new Dictionary<string, string> { { "If-Modified-Since", "2011-10-25T13:09:39.6242263-04:00" } });

        Console.WriteLine("Sending data in the future, ISO 8601 format (should return 304):");
        Util.SendRequest(baseAddress + "/GetData", "GET", null, null,
            new Dictionary<string, string> { { "If-Modified-Since", "2021-10-25T13:09:39.6242263-04:00" } });

        Console.WriteLine("Sending data in the past, RFC 1123 format (should return 200):");
        Util.SendRequest(baseAddress + "/GetData", "GET", null, null,
            new Dictionary<string, string> { { "If-Modified-Since", "Wed, 26 Oct 2011 01:00:00 GMT" } });

        Console.WriteLine("Sending data in the future, RFC 1123 format (should return 304):");
        Util.SendRequest(baseAddress + "/GetData", "GET", null, null,
            new Dictionary<string, string> { { "If-Modified-Since", "Mon, 27 Oct 2031 10:00:00 GMT" } });

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
public static class Util
{
    public static string SendRequest(string uri, string method, string contentType, string body)
    {
        return SendRequest(uri, method, contentType, body, null);
    }
    public static string SendRequest(string uri, string method, string contentType, string body, Dictionary<string, string> headers)
    {
        string responseBody = null;

        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
        req.Method = method;
        if (headers != null)
        {
            foreach (string headerName in headers.Keys)
            {
                switch (headerName)
                {
                    case "If-Modified-Since":
                        req.IfModifiedSince = DateTime.Parse(headers[headerName]);
                        break;
                    default:
                        req.Headers[headerName] = headers[headerName];
                        break;
                }
            }
        }
        if (!String.IsNullOrEmpty(contentType))
        {
            req.ContentType = contentType;
        }

        if (body != null)
        {
            byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
            req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
            req.GetRequestStream().Close();
        }

        HttpWebResponse resp;
        try
        {
            resp = (HttpWebResponse)req.GetResponse();
        }
        catch (WebException e)
        {
            resp = (HttpWebResponse)e.Response;
        }

        if (resp == null)
        {
            responseBody = null;
            Console.WriteLine("Response is null");
        }
        else
        {
            Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
            foreach (string headerName in resp.Headers.AllKeys)
            {
                Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
            }
            Console.WriteLine();
            Stream respStream = resp.GetResponseStream();
            if (respStream != null)
            {
                responseBody = new StreamReader(respStream).ReadToEnd();
                Console.WriteLine(responseBody);
            }
            else
            {
                Console.WriteLine("HttpWebResponse.GetResponseStream returned null");
            }
        }

        Console.WriteLine();
        Console.WriteLine("  *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*  ");
        Console.WriteLine();

        return responseBody;
    }
}
于 2011-10-27T21:10:22.820 回答