2012-10-03 15 views
14

Znalazłem skrypt na this site dla uruchamiania prostego serwera za pomocą wiersza poleceń z pythonem.Jak mogę debugować żądania POST przy użyciu BaseHTTPServer/SimpleHTTPServer Pythona?

Dodałem kilka linii print, ponieważ chciałbym wydrukować parametry GET i POST za pomocą wiersza poleceń dla żądań, ale nie mogę sprawić, żeby pojawiły się w dowolnym miejscu.

Gdybym po prostu wydrukować naszą naszą ten s zmienną (pprint (vars(s))) skończę widząc to:

{'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>} 

Próbowałem następnie użyć polecenia print z każdego z indeksów (pprint (vars(s.connection))), ale to nie działa .

Oto zmodyfikowany skrypt:

#!/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) 

Jak mogę wydrukować POST i GET parametrów za pomocą prostego skryptu?

Pożądany wyjście poprzez linię poleceń będzie wyglądać następująco:

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

Odpowiedz

23

nie jest to ogromnie oczywiste, ale jest przy użyciu programu obsługi gniazd za kulisami. Musisz więc odczytać surowe dane z gniazda, a następnie je zinterpretować.

Użyj modułu urlparse.

  • W Pythonie 2, chcesz urlparse.parse_qs.
  • W języku Python 3 nazwa biblioteki została zmieniona: chcesz uzyskać urllib.parse.parse_qs.

importu urlparse, a następnie zmodyfikować metoda do_POST tak:

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() 
     ... 

Konfigurowanie prostego klienta testowego:

#!/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 

uruchomić serwer, a następnie uruchomić klienta:

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

To powinno być '' bis' baz' nie :) –

+0

@Piotr Dobrogost - Just poniższym przykładzie OP - weź go ze sobą! :) –

5

You można użyć modułu cgi zamiast urlparse. cgi implementuje paramery POST parsujące po wyjęciu z pudełka. Korzystanie z dobrze przetestowanych bibliotek wydaje się lepsze.

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) 
Powiązane problemy