我正在实现一个F#-ish web请求函数,如下所示:
let request
(httpMethod:string)
(url:string)
(headers:Header list)
(content:Content option)=
let groupHeaders (headers:WebHeaderCollection) =
let d = new Dictionary<string, string list> ()
let addToDict h =
let oldValue = if d.ContainsKey(h) then d.Item(h) else []
d.Item(h) <- oldValue @ [headers.Get h]
headers.AllKeys |> Array.iter addToDict
d |> Seq.map (|KeyValue|) |> Map.ofSeq
async {
let rq = WebRequest.Create(url) :?> HttpWebRequest
rq.Method <- httpMethod
headers
|> List.iter (fun (key, value) -> rq.Headers.Add(key, value) |> ignore )
match content with
| Some (contentType, bytes) ->
rq.ContentType <- contentType
do! rq.GetRequestStream().AsyncWrite(bytes)
| None -> ()
try
use! response = rq.AsyncGetResponse()
let webResponse = response :?> HttpWebResponse
let responseCode = webResponse.StatusCode
let stream = webResponse.GetResponseStream()
let length = webResponse.ContentLength |> int32 //TODO what if the data is bigger then 4GB?
let! bytes = stream.AsyncRead(length)
let respHeaders = groupHeaders webResponse.Headers
return
match webResponse.StatusCode with
| HttpStatusCode.OK -> OK (respHeaders, bytes)
| HttpStatusCode.NotFound -> NotFound
| otherCode -> Error <| otherCode.ToString()
with
| :? WebException as ex ->
return Error <| ex.Status.ToString()
}
问题在于,如果我尝试获取返回riak
的页面(尝试获取404
值),则结果为WebException
,并显示消息The remote server returned an error: (404) Not Found.
而不是HttpStatusCode.NotFound
对同一网址执行curl GET
会得到以下结果:
$ curl -v http://localhost:18098/riak/user/asfasfd?returnbody=true
* About to connect() to localhost port 18098 (#0)
* Trying ::1...
* connected
* Connected to localhost (::1) port 18098 (#0)
> GET /riak/user/asfasfd?returnbody=true HTTP/1.1
> User-Agent: curl/7.27.0
> Host: localhost:18098
> Accept: */*
>
* additional stuff not fine /usr/src/ports/curl/curl-7.27.0-1/src/curl-7.27.0/lib/transfer.c:1037: 0 0
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 404 Object Not Found
< Server: MochiWeb/1.1 WebMachine/1.9.0 (someone had painted it blue)
< Date: Sun, 28 Oct 2012 05:30:12 GMT
< Content-Type: text/plain
< Content-Length: 10
<
not found
* Connection #0 to host localhost left intact
* Closing connection #0
为什么抛出异常WebException
的任何想法?
如果我想确定404页面未找到的情况,我有哪些选项而不是解析异常消息?
答案 0 :(得分:3)
@desco是正确的,但详细说明了他的答案 - 以下是如何使用模式匹配来解决问题:
try
// Do stuff here
//
with
| :? WebException as webEx when (webEx.Response :? HttpWebResponse) ->
/// The exception's Response, as an HttpWebResponse.
/// From this we can get the HTTP status code of the response.
let httpWebResponse = webEx.Response :?> HttpWebResponse
// Return an error message based on the HTTP status code.
match httpWebResponse.StatusCode with
| HttpStatusCode.NotFound ->
return NotFound
| otherCode ->
return Error <| otherCode.ToString()
| :? WebException as webEx ->
return Error <| webEx.Status.ToString()
此外,您获得WebException的原因是因为HttpWebResponse
处理4xx和5xx响应代码的方式。您检查match
的代码中的webResponse.StatusCode
语句将不会达到HttpStatusCode.NotFound
大小写,因为会抛出异常。您应该保留match
,以处理任何非HttpStatusCode.OK
的非错误代码(例如,301重定向)。
答案 1 :(得分:1)
WebException有2个属性可以帮助您: