我在盈透证券有一个账户。他们有一个不错的交易 API,但没有 API 来访问通过其网站 https://www.interactivebrokers.com/sso/Login 。我看了一点 JavaScript,他们正在加密用户名和密码。密码在浏览器中的 JavaScript 中,然后通过 SSL 发送加密的内容。
我希望能够在 C# 中做到这一点。第一步(我认为)是打开 https://www.interactivebrokers.com/sso/Login< /a> 使用 HttpWebRequest 或 WebClient 来获取会话 ID(这只是加载登录页面 - 甚至还没有输入任何用户名或密码)。
代码中没有什么太具有突破性的东西。 WebClient 版本是:
WebClient client = new WebClient();
client.Encoding = Encoding.UTF8;
Stream data = client.OpenRead("https://www.interactivebrokers.com/sso/Login");
HttpWebRequest 版本没什么可写的:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.interactivebrokers.com/sso/Login");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
但是,在任何一种情况下,当我这样做时,我都会得到一个
The remote server returned an error: (400) Bad Request.
我试图添加用户代理,按照 为什么我的 HttpWebRequest 返回 400 错误请求?:
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
我
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)";
仍然收到 (400) 错误。
内部异常为空,但查看 WebException 的流显示以下响应(我不知道为什么标题显示“200 OK”):
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>200 OK</title>
</head><body>
<h1>OK</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body></html>
我查看了执行请求的 Web 浏览器和我的 C# 代码之间的数据包差异,我注意到的第一个区别是 Web 浏览器比我的 C# 代码有更多可用的密码套件。当服务器响应 Web 浏览器时,它会选择 C# 客户端中不可用的密码之一。如何将密码套件添加到 HttpWebRequest / WebClient?我还没有弄清楚这是否真的是问题所在。
我错过了一些非常基本的东西吗?为什么我什至无法使用 HttpWebRequest 或 WebClient 加载该页面?
谢谢
I have an account with Interactive Brokers. They have a decent trading API, but there is no API to access some of the account management features that are available through their web site at https://www.interactivebrokers.com/sso/Login . I looked at the javascript a bit, and they are encrypting the user name & password in the browser in javascript, and then sending the encrypted stuff over SSL.
I'm hoping to be able to do that in c#. The first step (I think) is to open https://www.interactivebrokers.com/sso/Login using an HttpWebRequest or WebClient, to get a session ID (this is just loading the login page -- not even entering any username or password yet).
There's nothing too ground-breaking in the code. The WebClient version is:
WebClient client = new WebClient();
client.Encoding = Encoding.UTF8;
Stream data = client.OpenRead("https://www.interactivebrokers.com/sso/Login");
The HttpWebRequest version is nothing to write home about either:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.interactivebrokers.com/sso/Login");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
However, in either case when I do that, I get a
The remote server returned an error: (400) Bad Request.
I tried to add a user agent, as per Why Does my HttpWebRequest Return 400 Bad request? :
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
and
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)";
I still get the (400) error.
The inner exception is null, but looking at the WebException's stream shows the following response (I don't know why the title says '200 OK'):
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>200 OK</title>
</head><body>
<h1>OK</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body></html>
I looked at the difference in packets between a web browser doing the request and my c# code, and the first difference I noticed is that the web browser has many more cypher suites available to it then my c# code. When the server responds to the web browser, it chooses one of the cyphers that is not available in the c# client. How do I add cypher suites to HttpWebRequest / WebClient? I haven't yet figured out if that is actually the problem or not.
Am I missing something really basic? Why can't I even load that page with an HttpWebRequest or WebClient?
Thanks
发布评论
评论(1)
事实证明,需要两个标头(HttpWebRequest 上的属性):UserAgent 和 UserAgent。接受。这是我应该用 WireShark 发现的,但使用 Fiddler 可以更容易地比较标头。我的速度变慢了,因为我正在比较 fiddler 中的 CONNECT 会话,并且更改 useragent 不会影响连接标头(不太清楚为什么,但我想这并不重要)。 CONNECT 后的下一行正确反映了我在 HttpWebRequest 上设置的属性,然后我就能够找出问题所在。
感谢埃里克·劳(Eric Law)激励我走向正确的方向。与 Cyphers 无关:)
It turns out that two headers (properties on HttpWebRequest) were required: UserAgent & Accept. It's something I should have spotted with WireShark, but using Fiddler made it a bit easier to compare headers. I was slowed down because I was comparing the CONNECT sessions in fiddler, and changing the useragent doesn't affect the connect headers (don't really know why, but it doesn't matter I guess). The next line down after CONNECT properly reflected the properties that I set on HttpWebRequest, and I was then able to figure out what was wrong.
Thanks to Eric Law for stirring me in the right direction. Had nothing to do with Cyphers :)