LoginSignup
15
16

More than 5 years have passed since last update.

pythonでシンプルなHTTPサーバを作る

Posted at

目的

この記事はpythonで最もシンプルなコードでテスト用スタブHTTPサーバを作成する方法を紹介します。

背景

プロジェクト開発の時に、別チームが開発するサーバへHTTP通信する場合があります。しかし、開発進捗など理由で相手のプロジェクトが使えない時に、こちらのシステムを先に制作または試験の指示が来たことがあります。では、セキュリティやパフォーマンスなど考慮せず、最低のコストで、一時的なスタブを作成する方法はありますか。

解決案

  1. スタブの機能
    GETリクエストを受信し、HTMLページを戻します。
    POSTリクエストを受信し、特定値によって、事前に用意する結果をレスポンスとして戻します。

  2. 実装
    BaseHTTPRequestHandlerを拡張し、GETとPOSTを処理するメソッドを作る

    import os
    import sys
    import urllib.parse
    import html
    
    from http.server import BaseHTTPRequestHandler
    from http.server import HTTPServer
    from http import HTTPStatus
    
    PORT = 8000
    
    #-------------------------------------------------------
    data = {}
    data["1234123412341234"] = "test1,test2,123,455,24,5,6,,4,,4344356,,34,ert"
    data["0000000000000000"] = "testdata2"
    #-------------------------------------------------------
    
    class StubHttpRequestHandler(BaseHTTPRequestHandler):
        server_version = "HTTP Stub/0.1"
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
        def do_GET(self):
            enc = sys.getfilesystemencoding()
            title = "HTTP Stub"
    
            r = []
            r.append('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" '
                     '"http://www.w3.org/TR/html4/strict.dtd">')
            r.append('<html>\n<head>')
            r.append('<meta http-equiv="Content-Type" '
                     'content="text/html; charset=%s">' % enc)
            r.append('<title>%s</title>\n</head>' % title)
            r.append('<body>\n<h1>%s</h1>' % title)
            r.append('<hr>\n<ul>')
            r.append("Stub Opened.")
            r.append('</ul>\n<hr>\n</body>\n</html>\n')
            encoded = '\n'.join(r).encode(enc, 'surrogateescape')
    
            self.send_response(HTTPStatus.OK)
            self.send_header("Content-type", "text/html; charset=%s" % enc)
            self.send_header("Content-Length", str(len(encoded)))
            self.end_headers()
    
            self.wfile.write(encoded)     
    
        def do_POST(self):
            enc = sys.getfilesystemencoding()
    
            length = self.headers.get('content-length')
            nbytes = int(length)
            rawPostData = self.rfile.read(nbytes)
            decodedPostData = rawPostData.decode(enc)
            postData = urllib.parse.parse_qs(decodedPostData)
    
            pan = postData["PAN"]
    
            resultData = []
            for p in pan:
                resultData.append(data[p])
    
            encoded = '\n'.join(resultData).encode(enc)
            self.send_response(HTTPStatus.OK)
            self.send_header("Content-type", "text/plain; charset=%s" % enc)
            self.send_header("Content-Length", str(len(encoded)))
            self.end_headers()
    
            self.wfile.write(encoded)
    
    handler = StubHttpRequestHandler
    httpd = HTTPServer(('',PORT),handler)
    httpd.serve_forever()
    
  3. 検証
    まずはGETしてみます。ブラウザでアクセスして、ページが正常に表示できるはずです。
    次にPOSTを確認します。

    import urllib.request
    import urllib.parse
    
    # 特定HEADER送信の例です。このサンプルに未使用
    reqAddtionalHeaders = {
        'X-Request=Process':"01"
    }
    
    data = urllib.parse.urlencode({"PAN":"1234123412341234"})
    data = data.encode('utf-8')
    
    req = urllib.request.Request("http://localhost:8000", data,reqAddtionalHeaders)
    
    with urllib.request.urlopen(req) as f:
        print(f.read().decode('utf-8'))
    

検証環境

Windows10
Python3.7

最後

同機能なものは他の言語、例えばC#でのWCFかASP.NET、あるいはJAVAでのspringbootなどはもちろん、数多くのフレームワークができます。しかし、テスト用の一時的なもので、セキュリティ問題もエラー処理問題も不要な場合、やはりPythonが一番だと思います。環境の配置はほとんど必要なく、開発も短時間でできます。

15
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
16