带有空域的 HttpWebRequest cookie
我有一个 ASP.NET MVC 操作,它通过 HttpWebRequest 向另一台服务器发送 GET 请求。我想将原始操作请求中的所有 cookie 包含在新请求中。原始请求中的某些 System.Web.HttpCookie 具有空域值(即“”),这显然不会导致任何问题。当我使用每个 cookie 的名称、值、路径和域创建 System.Net.Cookie 并将其添加到请求的 CookieContainer 时,我收到以下错误:
"System.ArgumentException: 参数 '{0 }' 不能是空字符串。参数名称:cookie.Domain"
下面是一些会抛出相同错误的代码(当添加 cookie 时):
var request = (HttpWebRequest)WebRequest.Create("http://www.whatever.com");
request.Method = "GET";
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add ( new Cookie ( "MyCookieName", "MyCookieValue", "/", "") );
编辑
我有点通过使用“localhost”作为域来修复此问题,而不是原始 HttpCookie 中的 null 或空字符串值。那么,为什么空域不适用于 CookieContainer? HttpCookie 是否使用空值来表示 localhost,或者我是否需要找到另一个解决方案来解决此问题?
I have an ASP.NET MVC action that sends a GET request to another server via HttpWebRequest. I'd like to include all cookies in the original action's request in the new request. Some of the System.Web.HttpCookies in the original request have empty domain values (i.e. ""), which apparently doesn't cause any issues. When I create a System.Net.Cookie using the name, value, path, and domain of each of these cookies and add it to the request's CookieContainer, I get this error:
"System.ArgumentException: The parameter '{0}' cannot be an empty string. Parameter name: cookie.Domain"
Here's some code that will throw the same error (when the cookie is added):
var request = (HttpWebRequest)WebRequest.Create("http://www.whatever.com");
request.Method = "GET";
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add ( new Cookie ( "MyCookieName", "MyCookieValue", "/", "") );
EDIT
I sort of fixed this by using "localhost" for the domain, instead of the null or empty string value from the original HttpCookie. So, why does an empty domain not work for the CookieContainer? And does HttpCookie use an empty value to signify localhost, or do I need to find another fix for this problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
免责声明:
正如 @feroze 之前所说,将 cookie 的域设置为 localhost 对您来说效果不太好。我假设您正在编写一个帮助程序,允许您将 HTTP 请求通过隧道传输到外部域。请注意,这不是最佳实践,并且在很多情况下不需要(即 jQuery 有一个许多很酷的内置跨域支持,另请参阅新的CORS规范)。但有时您可能会陷入困境(即外部资源仅为 XML,并且位于不支持 CORS 的服务器上)。
有关 Cookie 域及其工作原理的背景信息:
如果您还没有查看HTTP Cookie:维基百科上的域和路径——几乎您需要知道的所有内容都在那里。
在评估 cookie 时,客户端(“本地”请求者)和 Web 服务器(“外部”响应者)两者都会考虑域和路径。当客户端请求资源时,客户端应该仅发送与域匹配的 cookie(或更通用的 父域)和所请求的 URI 的路径(或更通用的父路径)。
Web 浏览器可以正确处理这个问题。例如,如果网络浏览器具有域“localhost”的 cookie,并且您正在请求“google.com”,则“localhost”域的这些 cookie 将不会在请求中发送到“google.com”。 -- 事实上,大多数现代浏览器不仅不会发送它们,还会在收到的 Set-Cookie 响应标头中完全忽略它们(这些称为第三方 cookie - 允许您在您的浏览器中接受第三方 cookie) Web 浏览器是一个巨大的隐私/安全问题——不要这样做!)。
它也可以在另一个方向上工作——即使客户端不太可能在请求中包含第三方 cookie,如果确实如此,外部 Web 服务器应该忽略它(甚至一些用于正确域/路径的 cookie) ,以防止臭名昭著的 super-cookie 问题(即托管“example.com”的 Web 服务器应该。忽略属于其父域的 cookie:“.com”,因为“.com”是“公共后缀”))。
你应该做什么[如果你必须这样做]:
我为你推荐的行动方案是,当你读取客户端的 cookie 时(我不是 MVC 人员,但在常规 ASP.NET 中)这将在 Request.Cookies 中),循环遍历它们(确保过滤掉您自己网站的合法 cookie,尤其是 SessionId 等,或者正确使用 Path,这样它们就不会首先发送到此页面),然后添加一次将它们添加到传出请求的 cookie 集合中,将域重写为“www.whatever.com”(根据您的示例 - 如果您动态执行此操作,请将 URL 加载到新的 Uri() 对象中并使用.Host 属性),然后将 Path 设置为“/”。 -- 这将为向外部 Web 服务器发出的请求构建“Cookie”标头。
当该请求返回到您的服务器时,您需要检查它的传入响应是否有新的 cookie——这些 cookie 可以重新打包并以与我在上一段中说明的循环类型大致相同的方式发送回您的客户端,但您除外'需要将 Host 重写为 Request.Url.Host - 并且您需要将路径设置回“/”,除非您的 passthru 页面的路径是静态的(我猜它不是,因为您是使用 MVC),那么您需要将其设置为 Request.Url.AbsolutePath 例如。
快乐编码!
编辑:
此外,您还需要设置传出请求的 X-Forwarded-For 标记,以便您所调用的网站并不认为您的网络服务器是一个向其发送垃圾邮件的客户端。
Disclaimer:
As stated earlier by @feroze, setting your cookies' domain to localhost is not going to work out so well for you. I'm assuming you're writing a helper that allows you to tunnel HTTP requests out to foreign domains. Note that this is not best practice and in a lot of cases is not needed (i.e. jQuery has a lot of cool cross-domain support built-in, also see the new CORS specification). But sometimes you may be stuck doing this (i.e. the external resource is XML only, and is on a server that doesn't support CORS).
Background Information on Cookie Domains and How They Work:
If you haven't already take a look at HTTP Cookie: Domain and Path on Wikipedia -- pretty much everything you need to know is in there.
When evaluating a cookie, the Domain and Path are taken into account by both the client (the "local" requester) and the web server (the "foreign" responder). When a client requests a resource, the client should only send cookies where those cookies match the Domain (or a more generic parent domain) and Path (or a more generic parent path) of the URI being requested.
Web browsers handle this correctly. If a web browser has a cookie for the domain "localhost" and you're requesting "google.com", for example, those cookies for the "localhost" domain won't be sent in the request to "google.com". -- In fact, most modern browsers won't just not send them, they'll completely ignore them in Set-Cookie response headers that they receive (these are called third-party cookies -- enabling the acceptance of third party cookies in your web browser is a huge privacy/security concern -- don't do it!).
It works in the other direction as well -- even though it's unlikely for a client to include a third party cookie in a request, if it does, the foreign web server is supposed to ignore it (and even some cookies for correct domains/paths, so as to prevent the infamous super-cookie issue. (i.e. The web server hosting "example.com" should ignore cookies belonging to its parent domain: ".com", because ".com" is a "public suffix")).
What You Should Do [if you have to]:
The course of action I recommend for you, is when you read in your client's cookies (I'm not an MVC guy, but in regular ASP.NET this would be in Request.Cookies), loop through them (make sure to filter out your own site's legitimate cookies, especially SessionId, etc -- or use Path properly so they never get sent to this page in the first place), then add them one at a time to the outgoing request's cookie collection, rewriting the domain to be "www.whatever.com" (per your example -- if you're doing this dynamically, load the URL into a new Uri() object and use the .Host property), and then set the Path to "/". -- This will build the "Cookie" header for the outgoing request to the foreign web server.
When that request returns to your server, you then need to check it's incoming response for new cookies -- those cookies can be repackaged and sent back down to your client in much the same type of loop as I illustrated in the previous paragraph, except you'll want to rewrite Host to be Request.Url.Host -- and you'll want to set path back to "/" unless the path to your passthru page is static (I'm guessing it isn't since you're using MVC) then you'd want to set it to Request.Url.AbsolutePath for instance.
Happy Coding!
EDIT:
Also, you'll want to set the X-Forwarded-For tag of the outgoing request, so that the website you're calling doesn't think your web server is one single client that's been spamming the crap out of them.
不确定它能解决您的问题。但是要添加不带“Domain”属性的 cookie,您必须使用
HttpRequestHeader.Cookie
将 cookie 添加到标头,如下所示。希望有帮助!
Not sure it solves your problem. But to add cookies without the "Domain" property you must add to the headers the cookies using
HttpRequestHeader.Cookie
as follows.Hope it helps!
一些背景
发生这种情况是因为 CookieContainer 是客户端容器,旨在跨多个 HttpWebRequest 重用。重用它可以提供预期的 cookie 行为,即远程主机设置的 cookie 会随针对同一主机的每个后续 HttpWebRequest 一起发回。
由于重用,CookieContainer 实际上可能包含来自多个请求和/或主机的 cookie。
因此,为了确定容器中的哪些 cookie 需要通过特定的 HttpWebRequest 发送到某个主机(域),CookieContainer 检查 Domain 和 Path 属性。
这就是为什么 CookieContainer 中的 Cookie 需要有一个有效的域。
相反,在服务器端 cookie 是通过不同类型CookieCollection 传递的,它是一个简单的 cookie 列表,没有额外的逻辑。
具体来说,在您的情况下,在将 cookie 从 CookieCollection 复制到 CookieContainer 时,您需要将每个 cookie 的 Domain 属性设置为您要将请求转发到的域,以便 HttpWebRequest 知道在发送请求时包含 cookie 。
Some background
This occurs because CookieContainer is client-side container designed to be reused across multiple HttpWebRequest. Reusing it provides the expected cookie behavior that cookies set by the remote host are sent back with every subsequent HttpWebRequests targeted at the same host.
As a result of the reuse, a CookieContainer might actually contain cookies from multiple request and\or hosts.
So, in order to determine which of the cookies in the container need to be sent with a particular HttpWebRequest to some host (domain), CookieContainer examines the Domain and the Path property.
That's why a Cookie in a CookieContainer needs to have a valid Domain.
Conversely, on the server-side cookies are delivered via a different type, CookieCollection which a simple list of cookies with no extra logic.
Specifically, in your case, while copying cookies from the CookieCollection to the CookieContainer you need to set the Domain property of every cookie to the domain your are going to forward the request to, so that HttpWebRequest will know to include the cookies while sending the request.
您正在尝试将 cookie 发送到本地主机,对吗?
为什么不做这样的事情,给自己的机器一个真实的名称:
如果 cookie 属于 myname.com,您的浏览器或应用程序将无法识别其中的差异,并将 cookie 发送到 myname.com。
详细信息:
You are trying to get cookies sent to localhost, right?
Why don't you do something like this where you give your own machine a real name:
Your browser or app will not know the difference and send cookies to myname.com if that is where the cookie belongs.
Detailed info: