2017-06-30 54 views
-1

我無法用Python 3.5修復此問題。此代碼適用於Python早於3。我正在實現一個我需要用於Django應用程序的WSGI Web服務器。TypeError:需要類似字節的對象,而不是'str'WSGI服務器

文件的名稱是:webserver2.py。但他告訴我

TypeError: a bytes-like object is required, not 'str' 

你能幫我嗎?

import socket 
#import StringIO 
import io 
import sys 


class WSGIServer(object): 
    address_family = socket.AF_INET 
    socket_type = socket.SOCK_STREAM 
    request_queue_size = 1 

    def __init__(self, server_address): 
     # Create a listening socket 
     self.listen_socket = listen_socket = socket.socket(
      self.address_family, 
      self.socket_type 
     ) 
     # Allow to reuse the same address 
     listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
     # Bind 
     listen_socket.bind(server_address) 
     # Activate 
     listen_socket.listen(self.request_queue_size) 
     # Get server host name and port 
     host, port = self.listen_socket.getsockname()[:2] 
     self.server_name = socket.getfqdn(host) 
     self.server_port = port 
     # Return headers set by Web framework/Web application 
     self.headers_set = [] 

    def set_app(self, application): 
     self.application = application 

    def serve_forever(self): 
     listen_socket = self.listen_socket 
     while True: 
      # New client connection 
      self.client_connection, client_address = listen_socket.accept() 
      # Handle one request and close the client connection. Then 
      # loop over to wait for another client connection 
      self.handle_one_request() 

    def handle_one_request(self): 
     self.request_data = request_data = self.client_connection.recv(1024) 
     # Print formatted request data a la 'curl -v' 
     print(''.join(
      '< {line}\n'.format(line=line) 
      for line in request_data.splitlines() 
     )) 

     self.parse_request(request_data) 

     # Construct environment dictionary using request data 
     env = self.get_environ() 

     # It's time to call our application callable and get 
     # back a result that will become HTTP response body 
     result = self.application(env, self.start_response) 

     # Construct a response and send it back to the client 
     self.finish_response(result) 

    def parse_request(self, text): 
     request_line = text.splitlines()[0] 
     request_line = request_line.rstrip('\r\n') 
     # Break down the request line into components 
     (self.request_method, # GET 
     self.path,   # /hello 
     self.request_version # HTTP/1.1 
     ) = request_line.split() 

    def get_environ(self): 
     env = {} 
     # The following code snippet does not follow PEP8 conventions 
     # but it's formatted the way it is for demonstration purposes 
     # to emphasize the required variables and their values 
     # 
     # Required WSGI variables 
     env['wsgi.version']  = (1, 0) 
     env['wsgi.url_scheme'] = 'http' 
     env['wsgi.input']  = io.StringIO(self.request_data) 
     env['wsgi.errors']  = sys.stderr 
     env['wsgi.multithread'] = False 
     env['wsgi.multiprocess'] = False 
     env['wsgi.run_once']  = False 
     # Required CGI variables 
     env['REQUEST_METHOD'] = self.request_method # GET 
     env['PATH_INFO']   = self.path    # /hello 
     env['SERVER_NAME']  = self.server_name  # localhost 
     env['SERVER_PORT']  = str(self.server_port) # 8888 
     return env 

    def start_response(self, status, response_headers, exc_info=None): 
     # Add necessary server headers 
     server_headers = [ 
      ('Date', 'Tue, 31 Mar 2015 12:54:48 GMT'), 
      ('Server', 'WSGIServer 0.2'), 
     ] 
     self.headers_set = [status, response_headers + server_headers] 
     # To adhere to WSGI specification the start_response must return 
     # a 'write' callable. We simplicity's sake we'll ignore that detail 
     # for now. 
     # return self.finish_response 

    def finish_response(self, result): 
     try: 
      status, response_headers = self.headers_set 
      response = 'HTTP/1.1 {status}\r\n'.format(status=status) 
      for header in response_headers: 
       response += '{0}: {1}\r\n'.format(*header) 
      response += '\r\n' 
      for data in result: 
       response += data 
      # Print formatted response data a la 'curl -v' 
      print(''.join(
       '> {line}\n'.format(line=line) 
       for line in response.splitlines() 
      )) 
      self.client_connection.sendall(bytes(http_response, 'utf-8')) 
     finally: 
      self.client_connection.close() 


SERVER_ADDRESS = (HOST, PORT) = '', 8888 


def make_server(server_address, application): 
    server = WSGIServer(server_address) 
    server.set_app(application) 
    return server 


if __name__ == '__main__': 
    if len(sys.argv) < 2: 
     sys.exit('Provide a WSGI application object as module:callable') 
    app_path = sys.argv[1] 
    module, application = app_path.split(':') 
    module = __import__(module) 
    application = getattr(module, application) 
    httpd = make_server(SERVER_ADDRESS, application) 
    print('WSGIServer: Serving HTTP on port {port} ...\n'.format(port=PORT)) 
    httpd.serve_forever() 

的錯誤是:

enter image description here

+0

回溯是*文字*,請複製並粘貼到您的問題中。 –

+0

另外,這與Django無關,你在這裏從頭開始運行你自己的WSGI服務器。 –

回答

1

你傳遞一個字符串到這裏bytes方法:

request_line = request_line.rstrip('\r\n') 

request_linebytes對象,而不是str對象。您需要傳入一個bytes對象以剝離;使用b'...' bytesstring文字:

request_line = request_line.rstrip(b'\r\n') 

接下來,您要請求主體加載到StringIO對象,但你再有個字節。關於Python 3 WSGI使用二進制文件對象,而不是:

env['wsgi.input']  = io.BytesIO(self.request_data) 

但是,如果你正在嘗試做的是部署一個Django項目,就此打住吧。你做不是需要編寫你自己的WSGI服務器來實現。您找到的代碼是一個示例WSGI服務器,它不會在實際負載下保留,僅用於說明WSGI的工作方式。

對於Django部署,請閱讀How to deploy with WSGI documentation。您可能要閱讀how WSGI servers work

+0

@Erik:出於興趣,你爲什麼要從頭開始編寫WSGI服務器,而不是僅僅使用許多預先存在的WSGI服務器之一? –

+0

@Martin 因爲在我的大學裏,我的教授,爲了我的論文,告訴我在Django中創建一個Web應用程序,在這個Web應用程序中必須部署Web服務器來處理通過發佈請求訪問的區域。我發現很多困難。 – Erik

+0

@Erik:你確實不需要爲此編寫自己的WSGI服務器。 –

相關問題