2012-07-16 48 views
5

我正在做的HttpWebRequest到S3,和我想的日期头设置是这样的:C#HttpWebRequest的日期标题格式

“星期一,2012年7月16日1时16分十八秒 - 0000"

这里是我试过:

string pattern = "ddd, dd MMM yyyy HH:mm:ss -0000"; 
request.Date = DateTime.ParseExact("Mon, 16 Jul 2012 01:16:18 -0000", pattern, null); 

但是,当我看着请求的头,这是我得到:

request.Headers.Get("Date"); 
// "Mon, 16 Jul 2012 07:16:18 GMT" 

我相信这可能是403请求的原因。 AWS错误文档提及:

403禁止 - 请求时间和服务器时间的差异太大。

任何建议让这个日期整理出来将不胜感激。谢谢!

回答

13

有一些事情要澄清修复用手请求的情况下:

  • 你的日期模式不正确。

  • 的HttpWebRequest的request.Date头只能得到改性在.NET框架4并根据该文档中,命名空间System.Net将总是写此标头如使用GMT(UTC)格式标准形式。所以,无论你如何设置格式化日期,都无济于事!

  • 在其他.NET框架版本中,您将无法修改HttpWebRequest request.Date标头,因为它将使用实际日期,格式为正确的GMT(UTC)格式,除非您使用某种破解来设置自己的日期和格式(见下文)。


解决您的问题(测试工作):

你进口:

using System.Net; 
using System.Reflection; 

获取格式今天的日期:星期一,2012年7月16日01:16:18 - 0000

string today = String.Format("{0:ddd,' 'dd' 'MMM' 'yyyy' 'HH':'mm':'ss' 'K}", DateTime.Now); 

来了棘手的事情,你可以这样破解HttpWebRequest的日期标题:

(不要做request.Date = something;了,用下面的更换)

MethodInfo priMethod = request.Headers.GetType().GetMethod("AddWithoutValidate", BindingFlags.Instance | BindingFlags.NonPublic); 
priMethod.Invoke(request.Headers, new[] { "Date", today }); 

从您的请求中获取日期(仅用于测试):

// "myDate" will output the same date as the first moment: 
// Mon, 16 Jul 2012 01:16:18 -0000 
// As you can see, you will never get this again: 
// Mon, 16 Jul 2012 07:16:18 GMT 
string myDate = request.Headers.Get("Date"); 

在这一点上,你有你自己的格式和日期值成功设置为HttpWebRequest的日期头球攻门!

希望这有助于:-)

+1

你是男人。 – Mitciv 2012-07-16 18:16:33

+1

伟大的解决方案和示例。我必须为我的日期使用UNIX时间戳(十进制),这是一个完美的解决方案。干杯! – wloescher 2013-05-05 20:57:34

+1

我希望我能多劳多得!很好的回答:) – Winnie 2017-09-26 03:39:02

1

HttpWebRequest将自行正确格式化日期。你的问题是你必须提交一个有效的当前日期。你必须检查计算机的时钟是准确的,然后你要发送的正确日期有关的时区和UTC和GMT问题...

尝试两种:

request.Date = DateTime.Now; 
request.Date = DateTime.UtcNow; 

的那一个需要工作(如果HttpWebRequest被正确实现,两者都应该工作)。

在不工作,请使用fiddler看看发生了什么事,直到你得到它的工作

0

假设你要设置的日期标头Authorization头工作。

亚马逊提供了另一个自定义标题,它将用来代替日期(如果提供)。如果您无法设置Date标头,则可以使用自定义标头x-amz-date代替。

这里的链接到亚马逊的文档here

+0

请在这篇文章中发布更多信息,而不是简单地离开一个链接。这对未来的访问者更有用,在搜索中显示得更好,并且如果链接不好就会持续。 – 2013-05-17 18:30:02

0

您应该使用 “X-AMZ-日期” 标题。

public void GetObject(string AccessKeyID, string SecretKey){   
     /*objectKey = folder/folder/filename.zzz*/ 
     var url = "http://somehost/bucket/objectkey" 

     HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url); 
     /*Fiddler proxy*/ 
     /*request.Proxy = new WebProxy("http://127.0.0.1:8888");*/ 

     request.Headers.Add("X-Amz-Date",String.Format("{0:ddd,' 'dd' 'MMM' 'yyyy' 'HH':'mm':'ss' 'K}", DateTime.Now)); 
     request.Headers.Add("Authorization", $"AWS {AccessKeyID}:{SignAuthorizationString(request, SecretKey)}"); 

     WebResponse response = request.GetResponse(); 
     } 
private string SignAuthorizationString(HttpWebRequest request, string SecretKey){ 
     //TODO: DOCS - http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html 

     string canonicalizedResource = request.RequestUri.PathAndQuery; 
     string canonicalizedAmzHeaders = ComposeSignatureAmzHeadersForSigning(request); 
     string stringToSign = request.Method + "\n" 
           + request.Headers.Get("Content-MD5") + "\n" 
           + request.ContentType + "\n" 
           + request.Headers.Get("Date") + "\n" /*Here the date will be blank*/ 
           + canonicalizedAmzHeaders + canonicalizedResource; 

     return GetSignedMessage(SecretKey, stringToSign); 
     } 
private string ComposeSignatureAmzHeadersForSigning(HttpWebRequest request){ 
     SortedDictionary<string, string> headersDictionary = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase); 
     foreach (string _key in request.Headers.Keys) 
     { 
      key = _key.ToLower(); 
      if (key.StartsWith("x-amz")) 
      { 
       if ("x-amz-meta-reviewedby".Equals(key)) 
       { 
        if (headersDictionary.ContainsKey(key)) 
         headersDictionary[key] = headersDictionary[key] + "," + request.Headers[key]; 
        else 
         headersDictionary[key] = request.Headers[key]; 
       } 
       else 
        headersDictionary[key] = request.Headers.Get(key); 
      } 
     } 
     StringBuilder stringBuilder = new StringBuilder(); 
     foreach (var pair in headersDictionary) 
     { 
      stringBuilder.Append(pair.Key) 
       .Append(":") 
       .Append(pair.Value) 
       .Append("\n"); 

     } 
     return stringBuilder.ToString(); 
     } 
private static string GetSignedMessage(string key, string message){ 
     var crypt = HMACSHA1.Create(); 
     crypt.Key = Encoding.ASCII.GetBytes(key); 
     crypt.ComputeHash(Encoding.UTF8.GetBytes(message)); 

     return Convert.ToBase64String(crypt.Hash); 
     }