HttpWebRequest的未发送的所有Cookie [英] HttpWebRequest is not sending all cookies
问题描述
我试图让我的应用程序对外部网站进行登录操作。我用下面的code:
昏暗ENC作为编码= Encoding.UTF8
昏暗的数据为字节()=无
昏暗的REQ作为HttpWebRequest的
REQ = CTYPE(Net.WebRequest.Create(URL),Net.HttpWebRequest)
req.Method =方法
req.CookieContainer = CookieJar
req.AllowAutoRedirect = FALSE
如果方法=POST然后
req.ContentType =应用/的X WWW的形式urlen codeD
数据= enc.GetBytes(的PostData)
如果Data.Length> 0然后
req.ContentLength = Data.Length
昏暗方通作为物流= req.GetRequestStream()
newStream.Write(数据,0,Data.Length)
newStream.Flush()
newStream.Close()
结束如果
结束如果
昏暗的响应,Net.HttpWebResponse = CTYPE(req.GetResponse(),Net.HttpWebResponse)
昏暗ResponseStream作为IO.StreamReader =新IO.StreamReader(Response.GetResponseStream(),ENC)
昏暗的HTML作为字符串= ResponseStream.ReadToEnd()
Response.Close()
ResponseStream.Close()
返回HTML
什么工作:
- 的答复拥有所有正确的设置Cookie标题
- 在该容器中保存所有的权利饼干(共5)
有什么不工作:
- 所有cookie被正确地检索由容器。但是,并非所有的cookies沿蒙山下一个请求发送。 4饼干设置正确,但最重要的是不会被发送。
这是不发送的cookie是这个:
设置Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=.xxxxx.nl;Discard
此Cookie,并正确地发送饼干之间唯一的区别是,在它这其中有版本= 1和放弃...
没有任何人有任何想法,为什么所有检索到的cookie被发送,除了上面的那个?
任何帮助将是AP preciated!
这是一个的CookieContainer常见的已知的bug:链接在这里 的.NET版本低于4.0 的
注意设置Cookie标头的域:
曲奇#1 - >设置Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=marktplaats.nl;Discard
曲奇#2 - >设置Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=.marktplaats.nl;Discard
当URL格式是这样的HTTP cookie#1发送://marktplaats.nl / ...
//www.marktplaats.nl / ...
的HTTP cookie#2发送
因此,问题
这里的解决方案#1:(更好的和容易的)
类DomainComparer:StringComparer
{
公众覆盖INT比较(字符串x,y字符串)
{
如果(X == NULL ||ÿ== NULL)
{
返回StringComparer.OrdinalIgnoreCase.Compare(X,Y);
}
如果(x.StartsWith(WWW,StringComparison.OrdinalIgnoreCase))
{
X = x.Substring(4);
}
如果(y.StartsWith(WWW,StringComparison.OrdinalIgnoreCase))
{
Y = y.Substring(4);
}
返回StringComparer.OrdinalIgnoreCase.Compare(X,Y);
}
公众覆盖布尔等于(字符串x,y字符串)
{
返回比较(X,Y)== 0;
}
公众覆盖INT GetHash code(字符串OBJ)
{
如果(obj.StartsWith(WWW,StringComparison.OrdinalIgnoreCase))
{
物镜= obj.Substring(4);
}
返回StringComparer.OrdinalIgnoreCase.GetHash code(OBJ);
}
}
///<总结>
///这是一个hackfix为微软的bug,其中Cookie不会之间www.domain.com和domain.com共享
///< /总结>
///< PARAM NAME =CC>< /参数>
静态无效ImproveCookieContainer(REF的CookieContainer CC)
{
哈希表的表=(哈希表)cc.GetType()。InvokeMember(
m_domainTable
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance,
空,CC,新的对象[] {});
VAR比较器preperty = table.GetType()。getfield命令(_ keycomparer
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance);
如果(比较器preperty!= NULL)
{
比较器preperty.SetValue(表中,新DomainComparer());
}
}
解#1,只要您创建的CookieContainer的实例只要调用方法一旦实施
无效的主要()
{
的CookieContainer cookieJar =新的CookieContainer();
ImproveCookieContainer(REF cookieJar);
//然后用它与WebRequest对象
}
这里的解决方案#2:
- 请不要使用。新增(饼干),只能使用。新增(URI,饼干)方法。
-
通话BugFix_CookieDomain每次添加一个cookie的容器或
在使用之前.GetCookie或之前系统使用的容器。
私人无效BugFix_CookieDomain(的CookieContainer的CookieContainer)
{
System.Type的_ContainerType = typeof运算(的CookieContainer);
哈希表的表=(哈希表)_ContainerType.InvokeMember(m_domainTable
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.GetField |
System.Reflection.BindingFlags.Instance,
空值,
的CookieContainer,
新对象[] {});
ArrayList的键=新的ArrayList(table.Keys);
的foreach(在钥匙串keyObj)
{
字符串键=(keyObj为字符串);
如果(键[0] =='。')
{
字符串则newkey = key.Remove(0,1);
表[则newkey] =表[keyObj]
}
}
}
所有信贷的解决方案I'm trying to have my application perform a login action on an external website. I use the following code:
Dim enc As Encoding = Encoding.UTF8
Dim Data As Byte() = Nothing
Dim req As HttpWebRequest
req = CType(Net.WebRequest.Create(URL), Net.HttpWebRequest)
req.Method = method
req.CookieContainer = CookieJar
req.AllowAutoRedirect = False
If method = "POST" Then
req.ContentType = "application/x-www-form-urlencoded"
Data = enc.GetBytes(PostData)
If Data.Length > 0 Then
req.ContentLength = Data.Length
Dim newStream As Stream = req.GetRequestStream()
newStream.Write(Data, 0, Data.Length)
newStream.Flush()
newStream.Close()
End If
End If
Dim Response As Net.HttpWebResponse = CType(req.GetResponse(), Net.HttpWebResponse)
Dim ResponseStream As IO.StreamReader = New IO.StreamReader(Response.GetResponseStream(), enc)
Dim Html As String = ResponseStream.ReadToEnd()
Response.Close()
ResponseStream.Close()
Return Html
What works:
- The responses have all the proper "Set-Cookie" headers
- The container saves all the right cookies (5 in total)
What doesn't work:
- All cookies are correctly being retrieved by the container. But not all cookies are sent along whith the next request. 4 cookies are set correctly but the most important one is not sent.
The cookie that is not send is this one:
Set-Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=.xxxxx.nl;Discard
The only difference between this cookie and the cookies that are correctly sent is that this one has "Version=1" and "Discard" in it...
Does anybody have any idea why all retrieved cookies are sent except for the one above?
Any help would be appreciated!
解决方案 This is a common known bug in CookieContainer : Link Here for .Net version below 4.0
Notice the Domain of Set-Cookie Header:
Cookie # 1 -> Set-Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=marktplaats.nl;Discard
Cookie # 2 -> Set-Cookie: mpSecurity="ODc2NzM2ODoxMzUODViNTg5OWM1NTNlOWMwYmMxYjUxNWZjYzJjOGQyZGU4MTc2M2M=";Version=1;Path=/;Domain=.marktplaats.nl;Discard
Cookie #1 is sent when the URL format is like http://marktplaats.nl/...
Cookie #2 is sent when the URL format is like http://www.marktplaats.nl/...
Hence the problem
Here the solution # 1: (better and easy one)
class DomainComparer : StringComparer
{
public override int Compare(string x, string y)
{
if (x == null || y == null)
{
return StringComparer.OrdinalIgnoreCase.Compare(x, y);
}
if (x.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
{
x = x.Substring(4);
}
if (y.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
{
y = y.Substring(4);
}
return StringComparer.OrdinalIgnoreCase.Compare(x, y);
}
public override bool Equals(string x, string y)
{
return Compare(x, y) == 0;
}
public override int GetHashCode(string obj)
{
if (obj.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
{
obj = obj.Substring(4);
}
return StringComparer.OrdinalIgnoreCase.GetHashCode(obj);
}
}
/// <summary>
/// this is a hackfix for microsoft bug, where cookies are not shared between www.domain.com and domain.com
/// </summary>
/// <param name="cc"></param>
static void ImproveCookieContainer(ref CookieContainer cc)
{
Hashtable table = (Hashtable)cc.GetType().InvokeMember(
"m_domainTable",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance,
null, cc, new object[] { });
var comparerPreperty = table.GetType().GetField("_keycomparer",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance);
if (comparerPreperty != null)
{
comparerPreperty.SetValue(table, new DomainComparer());
}
}
Implementation of Solution # 1, whenever you create a instance of CookieContainer just call the method once
void main()
{
CookieContainer cookieJar = new CookieContainer();
ImproveCookieContainer(ref cookieJar);
// then use it with the WebRequest object
}
Here the solution # 2:
- Don't use .Add(Cookie), Use only .Add(Uri, Cookie) method.
Call BugFix_CookieDomain each time you add a cookie to the container or
before you use .GetCookie or before system use the container.
private void BugFix_CookieDomain(CookieContainer cookieContainer)
{
System.Type _ContainerType = typeof(CookieContainer);
Hashtable table = (Hashtable)_ContainerType.InvokeMember("m_domainTable",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.GetField |
System.Reflection.BindingFlags.Instance,
null,
cookieContainer,
new object[] { });
ArrayList keys = new ArrayList(table.Keys);
foreach (string keyObj in keys)
{
string key = (keyObj as string);
if (key[0] == '.')
{
string newKey = key.Remove(0, 1);
table[newKey] = table[keyObj];
}
}
}
All Credit for the solution to CallMeLaNN
这篇关于HttpWebRequest的未发送的所有Cookie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!