1.瀏覽器請求動態頁面過程

2.WSGI
Python Web Server Gateway Interface (或簡稱 WSGI,讀作“wizgy”)。
WSGI允許開發者將選擇web框架和web服務器分開。可以混合匹配web服務器和web框架,選擇一個適合的配對。比如,可以在Gunicorn 或者 Nginx/uWSGI 或者 Waitress上運行 Django, Flask, 或 Pyramid。真正的混合匹配,得益於WSGI同時支持服務器和架構.
web服務器必須具備WSGI接口,所有的現代Python Web框架都已具備WSGI接口,它讓你不對代碼作修改就能使服務器和特點的web框架協同工作。
WSGI由web服務器支持,而web框架允許你選擇適合自己的配對,但它同樣對於服務器和框架開發者提供便利使他們可以專注於自己偏愛的領域和專長而不至於相互牽制。其他語言也有類似接口:java有Servlet API,Ruby 有 Rack。
3.定義WSGI接口
WSGI接口定義非常簡單,它只要求Web開發者實現一個函數,就可以響應HTTP請求。我們來看一個最簡單的Web版本的“Hello World!”:
def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return 'Hello World!'
上面的 application( ) 函數就是符合WSGI標准的一個HTTP處理函數,它接收兩個參數:
- environ:一個包含所有HTTP請求信息的dict對象;
- start_response:一個發送HTTP響應的函數。
整個application( )函數本身沒有涉及到任何解析HTTP的部分,也就是說,把底層web服務器解析部分和應用程序邏輯部分進行了分離,這樣開發者就可以專心做一個領域了.
application( )函數必須由WSGI服務器來調用。有很多符合WSGI規范的服務器。而我們此時的web服務器項目的目的就是做一個極可能解析靜態網頁還可以解析動態網頁的服務器
實現代碼:
import time,multiprocessing,socket,os,re class MyHttpServer(object): def __init__(self): serveSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.serveSocket = serveSocket self.HTMLPATH = './html' def bind(self,port=8000): self.serveSocket.bind(('',port)) def start(self): self.serveSocket.listen() while True: clientSocket, clientAddr = self.serveSocket.accept() print(clientSocket) multiprocessing.Process(target=self.serveHandler, args=(clientSocket, clientAddr)).start() clientSocket.close() def serveHandler(self,clientSocket,clientAddr): try: recvData = clientSocket.recv(1024).decode('gbk') fileName = re.split(r' +', recvData.splitlines()[0])[1] filePath = self.HTMLPATH if fileName.endswith('.py'): try: pyname=fileName[1:-3] # 導入 pyModule = __import__(pyname) env={} responseBody = pyModule.application(env,self.startResponse) responseLine = self.responseLine responseHeader = self.responseHeader except ImportError: responseLine = 'HTTP/1.1 404 NOT FOUND' responseHeader = 'Server: ererbai' + os.linesep responseHeader += 'Date: %s' % time.ctime() responseBody = '<h1>很抱歉,服務器中找不到你想要的內容<h1>' else: if '/'== fileName: filePath += '/index.html' else: filePath += fileName try: file = None file =open(filePath,'r',encoding='gbk') responseBody = file.read() responseLine = 'HTTP/1.1 200 OK' responseHeader = 'Server: ererbai' + os.linesep responseHeader += 'Date:%s' % time.ctime() except FileNotFoundError: responseLine = 'HTTP/1.1 404 NOT FOUND' responseHeader = 'Server: ererbai' + os.linesep responseHeader += 'Date:%s' % time.ctime() responseBody = '很抱歉,服務器中找不到你想要的內容' finally: if (file!=None) and (not file.closed): file.close() except Exception as ex: responseLine = 'HTTP/1.1 500 ERROR' responseHeader = 'Server: ererbai' + os.linesep responseHeader += 'Date: %s' % time.ctime() responseBody = '服務器正在維護中,請稍后再試。%s'%ex finally: senData = responseLine + os.linesep + responseHeader + os.linesep + os.linesep + responseBody print(senData) senData = senData.encode('gbk') clientSocket.send(senData) if (clientSocket!=None) and ( not clientSocket._closed): clientSocket.close() def startResponse(self,status,responseHeaders): self.responseLine = status self.responseHeader = '' for k,v in responseHeaders: kv = k + ':' + v + os.linesep self.responseHeader += kv if __name__ == '__main__': server = MyHttpServer() server.bind(8000) server.start()
服務器中存在的html的文件:
- index.html
<html> <head> <title>首頁-畢業季</title> <meta http-equiv=Content-Type content="text/html;charset=gbk"> </head> <body>我們仍需共生命的慷慨與繁華相愛,即使歲月以刻薄和荒蕪相欺。 </body> </html>
- biye.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="gbk"> <title>畢業季</title> </head> <body> <br>當年以為六月不過也很平常 <br>當自己真正經歷了畢業 <br>才知道偶爾看到六月畢業季等字里所流露的種種想要重溫卻不敢提及的回憶 <br>畢業了 <br>那個夏天,我的畢業季,我的青春年少 <br>六月 <br>有人笑着說解脫,有人哭着說不舍 <br>那年, <br>你對我說的你好 <br>在不知不覺中 <br>變成了 <br>再見。 </body> </html>

mytime.py文件
import time def application(env,startResponse): status = 'HTTP/1.1 200 OK' responseHeaders = [('Server','bfe/1.0.8.18'),('Date','%s'%time.ctime()),('Content-Type','text/plain')] startResponse(status,responseHeaders) responseBody = str(time.ctime()) return responseBody
訪問結果:



''' 自定義的符合wsgi的框架 ''' import time class Application(object): def __init__(self, urls): '''框架初始化的時候需要獲取路由列表''' self.urls = urls def __call__(self, env, startResponse): ''' 判斷是靜態資源還是動態資源。 設置狀態碼和響應頭和響應體 :param env: :param startResponse: :return: ''' # 從請求頭中獲取文件名 fileName = env.get('PATH_INFO') # 判斷靜態還是動態 if fileName.startwith('/static'): fileName = fileName[7:] if '/' == fileName: filePath += '/index.html' else: filePath += fileName try: file = None file = open(filePath, 'r', encoding='gbk') responseBody = file.read() status = 'HTTP/1.1 200 OK' responseHeaders = [('Server', 'ererbai')] except FileNotFoundError: status = 'HTTP/1.1 404 Not Found' responseHeaders = [('Server', 'ererbai')] responseBody = '<h1>找不到<h1>' finally: startResponse(status, responseHeaders) if (file != None) and (not file.closed): file.close() else: isHas = False # 表示請求的名字是否在urls中,True:存在,False:不存在 for url, func in self.urls: if url == fileName: responseBody = func(env, startResponse) isHas = True break if isHas == False: status = 'HTTP/1.1 404 Not Found' responseHeaders = [('Server', 'ererbai')] responseBody = '<h1>找不到<h1>' startResponse(status, responseHeaders) return responseBody def mytime(env, startResponse): status = 'HTTP/1.1 200 OK' responseHeaders = [('Server', 'time')] startResponse(status, responseHeaders) responseBody = str(time.ctime()) return responseBody def mynews(env, startResponse): status = 'HTTP/1.1 200 OK' responseHeaders = [('Server', 'news')] startResponse(status, responseHeaders) responseBody = str('xx新聞') return responseBody '''路由列表''' urls = [ ('/mytime', mytime), ('/mynews', mynews) ] application = Application(urls)
學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入學習交流群
626062078,我們一起學Python!