我正在尝试使用“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值。
答案 0 :(得分:2)
首先,If-Modified-Since
是关于资源最后修改时间的条件GET,而ETag
是关于资源标识符的条件GET,所以请小心混合两个概念。
在WCF服务中实现对If-Modified-Since的支持的正确方法是使用CheckConditionalRetrieve
在DateTime
对象中传递WebOperationContext.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-services.aspx的WCF中找到关于条件GET支持的好文章。
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;
}
}