以下代码使用 FSharp.Data 的 Http 模块,在调用setProxy
时在函数Http.RequestString
中引发异常。在其他网站上使用query
参数而不是body
时,类似的代码也有效。什么可能导致问题? BTW,它在使用修改后的(用于分配代理)以前版本的Http模块时有效。
let headers = [ UserAgent ConfigurationManager.AppSettings.["UserAgent"] ]
let setProxy (req: HttpWebRequest) =
req.Proxy <- WebProxy(ConfigurationManager.AppSettings.["Proxy"], true)
req // Error here
let cc = CookieContainer()
let body = HttpRequestBody.FormValues [
"username", user;
"password", password;
"nothing.x", "21"; "nothing.y", "34"]
let html =
Http.RequestString("https://..../CheckLoginServlet",
httpMethod = "POST",
body = body, cookieContainer = cc, headers = headers,
customizeHttpRequest = setProxy )
例外:
System.dll中出现'System.InvalidOperationException'类型的异常,但未在用户代码中处理
附加信息:提交请求后无法执行此操作。
答案 0 :(得分:4)
我认为这是 FSharp.Data 库中的错误。通过它的source code on GitHub,我们可以将我们感兴趣的代码提取为:
let values = [ "id", "2"; ]
let req = WebRequest.Create("https://..../CheckLoginServlet") :?> HttpWebRequest
req.Method <- HttpMethod.Post
req.UserAgent <- "Magic"
req.AutomaticDecompression <- DecompressionMethods.GZip ||| DecompressionMethods.Deflate
let cookieContainer = new CookieContainer()
req.CookieContainer <- cookieContainer
req.ContentType <- "application/x-www-form-urlencoded"
let bytes = [ for k, v in values -> Uri.EscapeDataString k + "=" + Uri.EscapeDataString v ]
|> String.concat "&"
|> HttpEncodings.PostDefaultEncoding.GetBytes
let f = fun () -> async {
do! writeBody req bytes
let req = customizeHttpRequest req
let! resp = Async.FromBeginEnd(req.BeginGetResponse , req.EndGetResponse)
let stream = resp.GetResponseStream()
return! toHttpResponse
}
f()
问题出在writeBody
调用之前调用customizeHttpRequest
,而其代码为:
let writeBody (req:HttpWebRequest) (postBytes:byte[]) = async {
req.ContentLength <- int64 postBytes.Length
use! output = Async.FromBeginEnd(req.BeginGetRequestStream, req.EndGetRequestStream)
do! output.AsyncWrite(postBytes, 0, postBytes.Length)
output.Flush()
}
其中Async.FromBeginEnd(req.BeginGetRequestStream, req.EndGetRequestStream)
更改HttpWebRequest.m_RequestSubmitted
标志,然后由HttpWebRequest.Proxy
的属性设置器(与许多其他人一样)进行检查。我的建议:
HttpWebRequest
编写您自己的方法,do! writeBody req bytes
和let req = customizeHttpRequest req
来电的顺序注意:这可以在C#示例程序中轻松复制:
private static async void GetRequestStreamCallback(IAsyncResult ar)
{
HttpWebRequest req = (HttpWebRequest)ar.AsyncState;
Stream postStream = req.EndGetRequestStream(ar); // Here flag req.m_RequestSubmitted is true already
byte[] byteArray = Encoding.UTF8.GetBytes("id=1");
await postStream.WriteAsync(byteArray, 0, byteArray.Length);
postStream.Close();
req.Proxy = new WebProxy("localhost:8888", true);
allDone.WaitOne();
}
private static ManualResetEvent allDone = new ManualResetEvent(false);
static void Main(string[] args)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://localhost:64343/api/products");
req.Method = "POST";
req.UserAgent = "Magic";
req.AutomaticDecompression = DecompressionMethods.GZip;
req.CookieContainer = new CookieContainer();
req.ContentType = "application/x-www-form-urlencoded";
var bytes = Encoding.UTF8.GetBytes("id=2");
req.ContentLength = bytes.Length;
req.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), req);
allDone.WaitOne();
}
答案 1 :(得分:1)
这已在最新版本的F#Data
上修复