3

次のような F# っぽい 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値を取得しようとすると) 、応答ではなくメッセージが返されることです。404WebExceptionThe remote server returned an error: (404) Not Found.HttpStatusCode.NotFound

同じURLcurl 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 ページが見つからない状況を特定したい場合、例外メッセージを解析する代わりにどのようなオプションがありますか?

4

2 に答える 2

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に到達しません。ただし、そうでない非エラー コード(たとえば、301 リダイレクト)を処理するために、そこにHttpStatusCode.NotFound保持する必要があります。matchHttpStatusCode.OK

于 2012-10-28T17:03:16.273 に答える
1

WebException には、役立つ 2 つのプロパティがあります。

  1. タイプWebExceptionStatusのステータス。404 は ProtocolError によって示されるはずです
  2. Responseは、リモート ホストから返された応答を公開します。HttpWebResponse へのダウンキャスト応答とその使用Statusプロパティ
于 2012-10-28T08:22:15.133 に答える