【问题标题】:How can I debug POST requests with python's BaseHTTPServer / SimpleHTTPServer?如何使用 python 的 BaseHTTPServer / SimpleHTTPServer 调试 POST 请求?
【发布时间】:2012-10-03 20:10:09
【问题描述】:

我在this site 上找到了一个脚本,用于通过 python 命令行运行一个简单的服务器。

我添加了一些 print 行,因为我想通过命令行打印出请求的 GET 和 POST 参数,但我似乎无法让它们出现在任何地方。

如果我只打印我们的 s 变量 (pprint (vars(s))),我最终会看到:

{'client_address': ('127.0.0.1', 53373),
 'close_connection': 1,
 'command': 'GET',
 'connection': <socket._socketobject object at 0x10b6560c0>,
 'headers': <mimetools.Message instance at 0x10b689ab8>,
 'path': '/favicon.ico',
 'raw_requestline': 'GET /favicon.ico HTTP/1.1\r\n',
 'request': <socket._socketobject object at 0x10b6560c0>,
 'request_version': 'HTTP/1.1',
 'requestline': 'GET /favicon.ico HTTP/1.1',
 'rfile': <socket._fileobject object at 0x10b6538d0>,
 'server': <BaseHTTPServer.HTTPServer instance at 0x10b6893f8>,
 'wfile': <socket._fileobject object at 0x10b6536d0>}

然后我尝试对每个索引 (pprint (vars(s.connection))) 使用 print 命令,但这不起作用。

这是修改后的脚本:

#!/usr/bin/python
import time
import BaseHTTPServer
from pprint import pprint

HOST_NAME = 'localhost' # !!!REMEMBER TO CHANGE THIS!!!
PORT_NUMBER = 9000 # Maybe set this to 9000.


class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
        def do_HEAD(s):
                s.send_response(200)
                s.send_header("Content-type", "text/html")
                s.end_headers()
        def do_GET(s):
                """Respond to a GET request."""
                s.send_response(200)
                s.send_header("Content-type", "text/html")
                s.end_headers()
                s.wfile.write("<html><head><title>Title goes here.</title></head>")
                s.wfile.write("<body><form action='.' method='POST'><input name='x' value='1' /><input type='submit' /></form><p>This is a test.</p>")
                # If someone went to "http://something.somewhere.net/foo/bar/",
                # then s.path equals "/foo/bar/".
                s.wfile.write("<p>GET: You accessed path: %s</p>" % s.path)
                s.wfile.write("</body></html>")
                pprint (vars(s))
        def do_POST(s):
                """Respond to a POST request."""
                s.send_response(200)
                s.send_header("Content-type", "text/html")
                s.end_headers()
                s.wfile.write("<html><head><title>Title goes here.</title></head>")
                s.wfile.write("<body><p>This is a test.</p>")
                s.wfile.write("<body><form action='.' method='POST'><input type='text' name='xxxxxxxxxxxx' value='0000000000000000000000' /><input type='submit' /></form><p>This is a test.</p>")
                # If someone went to "http://something.somewhere.net/foo/bar/",
                # then s.path equals "/foo/bar/".
                s.wfile.write("<p>POST: You accessed path: %s</p>" % s.path)
                s.wfile.write("</body></html>")
                pprint (vars(s))
                pprint (vars(s.connection))
                pprint (vars(s.headers))
                pprint (vars(s.request))
                pprint (vars(s.rfile))
                pprint (vars(s.server))
                pprint (vars(s.wfile))
                pprint (vars(s.fp))
                """pprint (vars(s.request))"""

if __name__ == '__main__':
        server_class = BaseHTTPServer.HTTPServer
        httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
        print time.asctime(), "Server Starts - %s:%s" % (HOST_NAME, PORT_NUMBER)
        try:
                httpd.serve_forever()
        except KeyboardInterrupt:
                pass
        httpd.server_close()
        print time.asctime(), "Server Stops - %s:%s" % (HOST_NAME, PORT_NUMBER)

如何使用简单的脚本打印出 POST 和 GET 参数?

通过命令行所需的输出如下所示:

1.0.0.127. - - [03/Oct/2012 16:02:05] "POST / HTTP/1.1" 200 -
foo=1
bar=2
bis=3

【问题讨论】:

    标签: python http command-line


    【解决方案1】:

    这不是很明显,但处理程序在幕后使用套接字。所以你需要从socket中读取原始数据,然后进行解释。

    使用urlparse 模块。

    • 在 Python 2 中,您需要 urlparse.parse_qs
    • 在 Python 3 中,库被重命名:你想要urllib.parse.parse_qs

    导入urlparse,然后像这样修改你的do_POST方法:

    def do_POST(s):
            """Respond to a POST request."""
    
            # Extract and print the contents of the POST
            length = int(s.headers['Content-Length'])
            post_data = urlparse.parse_qs(s.rfile.read(length).decode('utf-8'))
            for key, value in post_data.iteritems():
                print "%s=%s" % (key, value)
    
            s.send_response(200)
            s.send_header("Content-type", "text/html")
            s.end_headers()
            ...
    

    设置一个简单的测试客户端:

    #!/usr/bin/env python
    
    import urllib
    import urllib2
    
    url = 'http://localhost:9000'
    post_dict = {'foo' : 1,
                 'bar' : 2,
                 'bis' : 3}
    
    params = urllib.urlencode(post_dict)
    post_req = urllib2.Request(url)
    post_req.add_data(params)
    
    response = urllib2.urlopen(post_req)
    response_data = response.read()
    response.close()
    print response_data
    

    启动服务器,然后运行客户端:

    ire@localhost$ python http_server.py 
    Wed Oct  3 21:38:51 2012 Server Starts - localhost:9000
    foo=[u'1']
    bar=[u'2']
    bis=[u'3']
    

    【讨论】:

    • 这应该是 baz 而不是 bis :)
    • @Piotr Dobrogost - 以 OP 为榜样 - 与他一起接受吧! :)
    【解决方案2】:

    您可以使用cgi 模块代替urlparsecgi 实现开箱即用的 POST 参数解析。使用经过良好测试的库似乎更好。

    import cgi

    def do_POST(self):
        form = cgi.FieldStorage(
            fp=self.rfile,
            headers=self.headers,
            environ={"REQUEST_METHOD": "POST"}
        )
    
        for item in form.list:
            print "%s=%s" % (item.name, item.value)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-12
      • 1970-01-01
      • 2012-09-20
      • 2014-02-19
      • 1970-01-01
      • 2016-02-04
      • 2021-05-14
      相关资源
      最近更新 更多