F#WebRequest抛出WebException(“协议错误”)而不是404状态代码

时间:2012-10-28 06:16:55

标签: f# httpwebrequest riak

我正在实现一个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页面未找到的情况,我有哪些选项而不是解析异常消息?

2 个答案:

答案 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个属性可以帮助您:

    类型为Status
  1. WebExceptionStatus。 404应由ProtocolError
  2. 表示
  3. Response公开远程主机返回的响应。对HttpWebResponse的下行响应及其使用Status属性