2014-12-17 6 views
4

Я пытаюсь сделать приложение, которое служит простой форме HTML для пользователя, а затем вызывает функцию, когда пользователь отправляет форму. Он использует wsgiref.simple_server для обслуживания HTML. Сервер сталкивается с ошибкой, и я не понимаю, почему. Код выглядит следующим образом:Ошибка при обслуживании html с WSGI

#!/usr/bin/python3 
from wsgiref.simple_server import make_server 
from wsgiref.util import setup_testing_defaults 
import webbrowser # open user's web browser to url when server is run 
from sys import exc_info 
from traceback import format_tb 

# Easily serves an html form at path_to_index with style at path_to_style 
# Calls on_submit when the form is submitted, passing a dictionary with key 
# value pairs { "input name" : submitted_value } 
class SimpleServer: 
    def __init__(self, port=8000, on_submit=None, index_path="./index.html", css_path="./style.css"): 
     self.port = port 
     self.on_submit = on_submit 
     self.index_path = index_path 
     self.css_path = css_path 

    # Forwards request to proper method, or returns 404 page 
    def wsgi_app(self, environ, start_response): 
     urls = [ 
      (r"^$", self.index), 
      (r"404$", self.error_404), 
      (r"style.css$", self.css) 
     ] 

     path = environ.get("PATH_INFO", "").lstrip("/") 
     # Call another application if they called a path defined in urls 
     for regex, application in urls: 
      match = re.search(regex, path) 
      # if the match was found, return that page 
      if match: 
       environ["myapp.url_args"] = match.groups() 
       return application(environ, start_response) 
     return error_404(environ, start_response) 

    # Gives the user a form to submit all their input. If the form has been 
    # submitted, it sends the ouput of self.on_submit(user_input) 
    def index(self, environ, start_response): 
     # user_input is a dictionary, with keys from the names of the fields 
     user_input = parse_qs(environ['QUERY_STRING']) 

     # return either the form or the calculations 
     index_html = open(self.index_path).read() 
     body = index_html if user_input == {} else calculate(user_input) 
     mime_type = "text/html" if user_input == {} else "text/plain" 

     # return the body of the message 
     status = "200 OK" 
     headers = [ ("Content-Type", mime_type), 
        ("Content-Length", str(len(body))) ] 
     start_response(status, headers) 
     return [body.encode("utf-8")] 


    def start_form(self): 
     httpd = make_server('', self.port, ExceptionMiddleware(self.wsgi_app)) 
     url = "http://localhost:" + str(self.port) 
     print("Visit " + url) 
     # webbrowser.open(url) 
     httpd.serve_forever() 

if __name__ == "__main__": 
    server = SimpleServer() 
    server.start_form() 

Когда я бегу, я получаю ошибку

127.0.0.1 - - [16/Dec/2014 21:15:57] "GET/HTTP/1.1" 500 0 
Traceback (most recent call last): 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 138, in run 
    self.finish_response() 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 180, in finish_response 
    self.write(data) 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 266, in write 
    "write() argument must be a bytes instance" 
AssertionError: write() argument must be a bytes instance 
127.0.0.1 - - [16/Dec/2014 21:15:57] "GET/HTTP/1.1" 500 59 
---------------------------------------- 
Exception happened during processing of request from ('127.0.0.1', 49354) 
Traceback (most recent call last): 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 138, in run 
    self.finish_response() 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 180, in finish_response 
    self.write(data) 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 266, in write 
    "write() argument must be a bytes instance" 
AssertionError: write() argument must be a bytes instance 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 141, in run 
    self.handle_error() 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 368, in handle_error 
    self.finish_response() 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 180, in finish_response 
    self.write(data) 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 274, in write 
    self.send_headers() 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 331, in send_headers 
    if not self.origin_server or self.client_is_modern(): 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 344, in client_is_modern 
    return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP/0.9' 
TypeError: 'NoneType' object is not subscriptable 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "/usr/lib/python3.4/socketserver.py", line 305, in _handle_request_noblock 
    self.process_request(request, client_address) 
    File "/usr/lib/python3.4/socketserver.py", line 331, in process_request 
    self.finish_request(request, client_address) 
    File "/usr/lib/python3.4/socketserver.py", line 344, in finish_request 
    self.RequestHandlerClass(request, client_address, self) 
    File "/usr/lib/python3.4/socketserver.py", line 669, in __init__ 
    self.handle() 
    File "/usr/lib/python3.4/wsgiref/simple_server.py", line 133, in handle 
    handler.run(self.server.get_app()) 
    File "/usr/lib/python3.4/wsgiref/handlers.py", line 144, in run 
    self.close() 
    File "/usr/lib/python3.4/wsgiref/simple_server.py", line 35, in close 
    self.status.split(' ',1)[0], self.bytes_sent 
AttributeError: 'NoneType' object has no attribute 'split' 

Этот вывод фактически не включать сценарий, я бегу, который я путаются. Есть предположения?

ответ

1

Глядя на ваш код, я не вижу прямой причины этой ошибки. Тем не менее, я бы настоятельно советовал, что, если вы не пытаетесь узнать, как работает wsgi (или реализовать свою собственную инфраструктуру), вы должны использовать существующую микро-инфраструктуру. WSGI НЕ предназначен для непосредственного использования приложениями. Он обеспечивает очень тонкий интерфейс между Python и веб-сервером.

Хороший и легкий каркас bottle.py - Я использую его для всех веб-приложений Python. Но есть много других, ищите «Non Full-Stack Frameworks» в https://wiki.python.org/moin/WebFrameworks.

Хорошим преимуществом бутылки является то, что это единственный файл, который позволяет легко распространять его с вашего сервера.

2

Чтобы зарегистрировать решение этой проблемы, проблема связана с функцией len().

ул (Len (тело))

Он рассчитать неправильный размер и когда вернуть сервер Content-Length, то ждать больше байт, что необходимо.

Таким образом, всегда посылает байты, используя буфер с UTF-8, следовать примеру:

from io import StringIO 
stdout = StringIO() 
print("Hello world!", file=stdout) 
start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')]) 
return [stdout.getvalue().encode("utf-8")]