none
Invoke-WebRequestの挙動について RRS feed

  • 質問

  • いつもお世話になっております。
    TeckNetの書き込みにはいつも助けられております。
    ありがとうございます。

    ”invoke-webrequest”を利用して簡易的なURL監視を行っています。
    ※取得したstatusが200なら正常と判定します。
    ※取得したstatusが200以外ならエラーと判定し、ポップが挙がります。

    コマンドの挙動について理解できない部分が有り困っています。
    テストで実際に監視しているURLにノイズ(ex.11111などを末尾に入れたり、URLの中間に入れたり)を
    入れて、挙動の確認をしているのですが、思った通りの動きをしてくれません。

    200のステータスコードが返り、Descriptionでokが返ります。
    また、全てのURLで一様の動きとならず、同じURLでもノイズを入れる場所によって
    挙動が変わります。

    コマンドの動きをみていると、コマンドではそのURLが正しく表示されるかどうかの判断はできないため、
    URLを叩いてWEBページから何かしらの反応が返れば『正常』と判断する様に見受けられます。
    ※WEBブラウザでURLを叩いてブラウザ上では404が返っても、コマンドは200を返す時があります。。

    コマンドの挙動について
    ・URLのコマンド判定
    ・URLの正否の判定にキャッシュ情報などが関与するか

    また、コマンドの挙動を変えたい場合、書き換えなどでるかなど
    何かお持ちの情報があればご教示頂けますと大変助かります。
    宜しくお願い致します。
    2018年11月21日 4:35

回答

  • もしかするとこのようなコードを書いていませんか?

    $response = Invoke-WebRequest "https://social.technet.microsoft.com/"
    $statusCode = $response.StatusCode
    if($statusCode -eq 200) {"正常"} else {"異常"}

    実はこのコード、サーバーがステータスコード200を返す時には正しく動作しますが、200以外の404等を返す時には正しく動作しません。

    というのも、Invoke-WebRequestコマンドレットは200以外のステータスコードが返されると、エラーが発生するため、$response変数には何も値が格納されません。(実際この仕様は酷いと思いますが)

    $response変数に、以前にステータスコード200で返却されたレスポンスが格納されている状態で新たにエラーが出ると、$response変数の中身が更新されないため、「実際には404なのに200が返された」ように見えてしまう現象が起きます。

    この現象の公式な回避方法は不明ですが、私は以下のようにしています。try catchステートメントを使って、正常時(200)にはそのままレスポンスからステータスコードを取り、エラー時(404等)には例外オブジェクトから取るようにします。

    $statusCode = 0
    $response = $null
    
    try
    {
        $response = Invoke-WebRequest https://social.technet.microsoft.com/
        $statusCode = $response.StatusCode
    }
    catch [System.Net.WebException]
    {
        $statusCode = $_.Exception.Response.StatusCode.value__
    }
    
    if($statusCode -eq 200) {"正常"} else {"異常"}

    これに加えて、キャッシュの問題もあります。Invoke-WebRequestは内部的に.NETのWebClientクラスを用いていて、このクラスはIEとキャッシュを共有しているようです。

    キャッシュを読まないようにする方法はいくつかありますが、一番単純なものは、アクセス毎にURIの末尾にランダムなクエリを付けるというものがあります。

    • 回答としてマーク みふさま 2018年11月21日 8:31
    2018年11月21日 5:58
    モデレータ

すべての返信

  • もしかするとこのようなコードを書いていませんか?

    $response = Invoke-WebRequest "https://social.technet.microsoft.com/"
    $statusCode = $response.StatusCode
    if($statusCode -eq 200) {"正常"} else {"異常"}

    実はこのコード、サーバーがステータスコード200を返す時には正しく動作しますが、200以外の404等を返す時には正しく動作しません。

    というのも、Invoke-WebRequestコマンドレットは200以外のステータスコードが返されると、エラーが発生するため、$response変数には何も値が格納されません。(実際この仕様は酷いと思いますが)

    $response変数に、以前にステータスコード200で返却されたレスポンスが格納されている状態で新たにエラーが出ると、$response変数の中身が更新されないため、「実際には404なのに200が返された」ように見えてしまう現象が起きます。

    この現象の公式な回避方法は不明ですが、私は以下のようにしています。try catchステートメントを使って、正常時(200)にはそのままレスポンスからステータスコードを取り、エラー時(404等)には例外オブジェクトから取るようにします。

    $statusCode = 0
    $response = $null
    
    try
    {
        $response = Invoke-WebRequest https://social.technet.microsoft.com/
        $statusCode = $response.StatusCode
    }
    catch [System.Net.WebException]
    {
        $statusCode = $_.Exception.Response.StatusCode.value__
    }
    
    if($statusCode -eq 200) {"正常"} else {"異常"}

    これに加えて、キャッシュの問題もあります。Invoke-WebRequestは内部的に.NETのWebClientクラスを用いていて、このクラスはIEとキャッシュを共有しているようです。

    キャッシュを読まないようにする方法はいくつかありますが、一番単純なものは、アクセス毎にURIの末尾にランダムなクエリを付けるというものがあります。

    • 回答としてマーク みふさま 2018年11月21日 8:31
    2018年11月21日 5:58
    モデレータ
  • お世話になっております。

    ご回答頂き、誠にありがとうございます。

    大変に参考になります。

    朧ながらに思っていたことに光を当てて頂き

    感謝致します。

    ご回答いただいた内容で対応致したく存じます。

    ありがとうございました!

    PS.先輩から薦められてご著書のポケットリファレンスを活用させて頂いております。

      今後とも宜しくお願い致します。

    2018年11月21日 8:30