工作と競馬2

電子工作、プログラミング、木工といった工作の記録記事、競馬に関する考察記事を掲載するブログ

PowerShellによるWebサーバーのスクリプト

概要

PowerShellを使って、ローカルWebサーバーを動かすスクリプトを作成した。


背景と目的

ある事情で、PowerShellを使って、ローカルWebサーバーを動かす必要が出たので、やり方を調べスクリプトを作成してみる。


詳細

0.調査

Web上の参考になったサイトをいくつか見つけた。


1.仕様

最低限動けばよい内容は、

  • GETリクエストで、htmlとjsonファイルを取得

だけとする。


2.実装

参考サイトほぼそのままであるが、ちょっと追加で実装。

# ポートとルートディレクトリ
$port = 8080
$root = "ルートディレクトリのパス"

# Ctrl+C用
[console]::TreatControlCAsInput = $true
Write-Host "Simple Http Server start."

# HTTP Serverのオブジェクトを建てる
$listener = New-Object system.net.HttpListener
$listener.Prefixes.Add('http://127.0.0.1:'+$port+'/')
$listener.Start()

while($true) {

    # Ctrl+C用
    if ([console]::KeyAvailable) {
        $key = [system.console]::readkey($true)
        if (($key.modifiers -band [consolemodifiers]"control") -and($key.key -eq "C")) {
            "Terminating..."
            break
        }
    }

    # アクセス待ち
    $context = $listener.GetContext() # block
    $request = $context.Request
    #$request # debug
    
    # リクエスト先
    $path = $root + $request.RawUrl.Replace("/", "\");
    $path

    # レスポンス処理
  $response = $context.Response
  if( Test-Path $path ) {
      # 要求されたURLに対応するコンテンツを返す
        "200 " + $request.RawUrl
        $page = (Get-Content -Path $path -Encoding UTF8) -join "`n"
        $buffer = [System.Text.Encoding]::UTF8.GetBytes($page)
        $ext = (Get-Item $path).Extension # 拡張子ごとにResponseのContent-Typeをつける
        if ($ext -eq ".html") { 
            $response.ContentType = "text/html"
        } elseif ($ext -eq ".json") {
            $response.ContentType = "application/json"
        } else {
            $response.ContentType = "text/plain"
        }
  } else {
      # パスが存在しないとき
      "404 " + $request.RawUrl
      $path2 = $root + "\error.html"
      $page = (Get-Content -Path $path -Encoding UTF8) -join "`n"
      $buffer = [System.Text.Encoding]::UTF8.GetBytes($page)
      $response.ContentType = "text/html"
  }
  $response.ContentLength64 = $buffer.Length
  $output = $response.OutputStream  
  $output.Write($buffer, 0, $buffer.Length)    

  $output.Close()
    
}

$listener.Stop()

ちょっと工夫が必要だったのが、以下の部分。

  • 改行コードをつける
$page = (Get-Content -Path $path -Encoding UTF8) -join "`n"
$buffer = [System.Text.Encoding]::UTF8.GetBytes($page)

最後の-join "`n"は、ブラウザからアクセスする場合には重要。Get-Contentコマンドは、行で分割した配列としてファイル内容を取得するようなので、次の行のUTF8.GetBytesを実行する前に、改行コードで連結しておく。これをやらないと、手元のChromeでは正しく表示されなかった。

  • Content-Typeをつける

htmlではなくても問題なかったが、クライアントアプリ上のjQueryなどでリクエストしてjsonを貰う場合は、つけてあるとブラウザ上で自動的にJSONオブジェクトに変換してくれた。ただし、拡張子ごとにつけないといけないので面倒。もっといい方法がありそうだ。。。


3.動作確認

以下のディレクトリにテスト用ファイルを配置。

C:\work\
    test.html
    test.json

ブラウザで、以下URLにアクセスし、正しく表示された。

http://localhost:8080/test.html

jsonのほうは、Pythonで以下を実行し、正しく取得できた。

import requests
resp = requests.get("http://localhost:8080/test.json")
print(resp.text)


まとめと今後の課題

PowerShellを使って、ローカルWebサーバーを動かすスクリプトを作成できた。