使用WSGI提供html时出错

时间:2014-12-17 05:24:09

标签: python wsgi wsgiref

我正在尝试创建一个为用户提供简单HTML表单的应用程序,然后在用户提交表单时调用函数。它使用wsgiref.simple_server来提供HTML。服务器遇到错误,我无法理解原因。代码如下:

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

这个输出实际上并不包含我正在运行的脚本,我很困惑。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

只是为这个问题注册解决方案,问题在于len()函数。

STR(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")]

答案 1 :(得分:1)

查看您的代码,我没有看到此错误的直接原因。但是,我强烈建议,除非您尝试了解wsgi的工作原理(或实现自己的框架),否则您应该使用现有的微框架。 WSGI并不意味着应用程序直接使用。它在Python和Web服务器之间提供了一个非常精简的接口。

一个漂亮而轻巧的框架是bottle.py - 我将它用于所有Python webapps。但是还有很多其他的,寻找"非全栈框架"在https://wiki.python.org/moin/WebFrameworks

瓶子的一个很好的优点是它只是一个文件,因此可以很容易地与您的服务器一起分发。