伺服器(server)根據[維基百科定義](https://zh.wikipedia.org/zh-tw/%E6%9C%8D%E5%8A%A1%E5%99%A8#%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%88%86%E7%B1%BB%EF%BC%88%E8%BD%AF%E4%BB%B6%EF%BC%89),為提供服務的電腦軟體,根據軟體種類可分為: - 檔案伺服器: NAS儲存裝置... - 網頁伺服器: Apache... - 資料庫伺服器: MySQL, MongoDB... 建置正式的伺服器需要諸多考量和維護;如果想檢查網頁專案的目前成果,或簡單分享電腦資源給其他協作者的話,可以透過python建立臨時的網頁伺服器。 在指定目錄內包含`index.html`就能預覽網頁,若沒有則會顯示當前資料夾結構。以下使用 `http.server` 模組建立靜態網頁伺服器 ## http.server 產生靜態伺服器 **注意:Python2 和 Python3 使用的模組不同,這裡介紹的為適用於Python3套件與使用方式** ### 下載並引入套件 ``` pip install httpserver import http.server from http.server import SimpleHTTPRequestHandler, HTTPServer ``` 還需多引入兩個物件: `SimpleHTTPRequestHandler` 和 `HTTPServer` 下面會簡單介紹他們的功能 ### 最簡單的建置伺服器程式碼 ``` ## example code to create and run the server from python docs def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler): server_address = ('', 8000) httpd = server_class(server_address, handler_class) httpd.serve_forever() ``` ### HTTPServer 和 SimpleHTTPRequestHandler `HTTPServer` 為socketserver.TCPServer的子類別,能建立一個伺服器實例 還需要給個 `RequestHandlerClass` 向HTTP提出請求與回應,有以下三種: - BaseHTTPRequestHandler - SimpleHTTPRequestHandler: 讀取與發佈當前目錄 (比較多人用此object) - CGIHTTPRequestHandler 最後給個協定版本(protocol) ``` HandlerClass = SimpleHTTPRequestHandler ServerClass = HTTPServer Protocol = "HTTP/1.0" ``` :star2: Handler 是什麼? ![image](https://hackmd.io/_uploads/HJxOqrw5C.png) 圖片引用自: https://blog.csdn.net/weixin_62079735/article/details/132797418 輸入伺服器相關資訊,包含ip位址,指定port(預設8000)等,並存為`httpd`變數 ``` if sys.argv[1:]: port = int(sys.argv[1]) else: port = 8000 server_address = ('127.0.0.1', port) HandlerClass.protocol_version = Protocol ## standard formula: ip + port + handlerclass httpd = ServerClass(server_address, HandlerClass) ``` 實體化與運作伺服器 `serve_forever()`可以透過 `shutdown()` 關閉 ``` sa = httpd.socket.getsockname() ## ('127.0.0.1' 8000) print ("Serving HTTP on", sa[0], "port", sa[1], "...") httpd.serve_forever() ``` console 顯示 GET ... 200 代表請求成功 ``` Serving HTTP on 127.0.0.1 port 8000 ... 127.0.0.1 - - "GET / HTTP/1.1" 200 - ``` 最後打開瀏覽器,輸入 `http://127.0.0.1:8000/` 或是 `http://${your_ip}:8000/` 就可看到成果了 ### 完整 co ``` # pip install httpserver import sys import http.server from http.server import SimpleHTTPRequestHandler, HTTPServer HandlerClass = SimpleHTTPRequestHandler ServerClass = HTTPServer Protocol = "HTTP/1.0" if sys.argv[1:]: port = int(sys.argv[1]) else: port = 8000 server_address = ('127.0.0.1', port) HandlerClass.protocol_version = Protocol httpd = ServerClass(server_address, HandlerClass) sa = httpd.socket.getsockname() ## ('127.0.0.1' 8000) print ("Serving HTTP on", sa[0], "port", sa[1], "...") httpd.serve_forever() ## it will print 127.0.0.1 - - "GET / HTTP/1.1" 200 - on console ## <-> to shutdown() ``` ### 觀看 html 效果 拿出之前寫的index.html 並放在指定路徑,透過 httpserver 產生 localhost 查看 html 網頁,若沒有 html 會顯示本機資料夾結構,可以透過這個方式與人分享網址,查看本機儲存的檔案內容 ## 動態伺服器與網路框架 網頁包含動態資訊如資料庫串接,自定義的網頁跳轉等,可利用python `flask` 達成。此模組提供伺服器端的網頁框架,協助高效率架設網站。 ### 下載與引入套件 這裡先引入最基本的 `Flask` 其他常用函數(`redirect, url_for, send_from_directory...`)會在後面介紹 ``` #pip install Flask from flask import Flask ``` ### 簡單的範例 - create `app.py` ``` # save this as app.py from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello, World!" if __name__ == '__main__': app.debug = True ## not shown in formal case app.run() ``` - 在 `app.py` 同層路徑下執行 `flask run` flask 會生成網頁於 http://127.0.0.1:5000/ ### 名詞和概念筆記 - flask 內含有 httpserver,但僅適合測試用,正式發布會建議用 **WSGI server** - 裝飾器(decorator): `@app.route` 做為路由,紀錄 URL/HTTP動作 與其對應的處理函式 - `@app.route('/')` 這裡的 `/` 代表 http://127.0.0.1:5000/ 這個URL - 若連結到此網址,會執行 hello() 函數並在網頁印出 Hello, World! - 若今天還有其他路由如下,打開 http://127.0.0.1:5000/**page/5** 就會看到函式執行結果 ``` app.route('/page/5') def welcome(): return "Welcome" ``` - flask 可以吃URL變數,方法為 `<variable_name>` ### flask 函式 `url_for` `redirect` `url_for()` 可以讓路由具有追蹤彈性,並搭配 `redirect()` 跳轉網頁 下面例子可知: http://127.0.0.1:5000/b 會被引導回 http://127.0.0.1:5000/ ``` from flask import url_for, redirect @app.route('/') def hello(): return 'hello' @app.route('/b') def b(): return redirect(url_for('hello')) ``` 其他套件如結合 html css 模板的`render_template`,或是上傳下載檔案的 `send_from_directory` 會在下篇介紹我的side project時補上~ ## References https://docs.python.org/3/library/http.server.html# https://chwang12341.medium.com/coding%E8%B5%B7%E4%BE%86-python-%E4%B8%80%E8%A1%8C%E6%8C%87%E4%BB%A4%E5%B0%B1%E8%83%BD%E8%BC%95%E9%AC%86%E5%BB%BA%E7%AB%8B%E7%B6%B2%E9%A0%81%E4%BC%BA%E6%9C%8D%E5%99%A8-simplehttpserver%E5%A5%97%E4%BB%B6-http-server%E4%BD%BF%E7%94%A8%E6%95%99%E5%AD%B8-34c30b81c26 https://hackmd.io/@peterju/B18gmJ7Ph#15Flask-%E7%B6%B2%E9%A0%81%E6%A1%86%E6%9E%B6 https://medium.com/@charming_rust_oyster_221/%E4%BD%BF%E7%94%A8-flask-%E5%89%B5%E5%BB%BA-web-api-%E7%AD%86%E8%A8%98-b5618543632e https://medium.com/@charming_rust_oyster_221/flask-%E6%AA%94%E6%A1%88%E4%B8%8A%E5%82%B3%E5%88%B0%E4%BC%BA%E6%9C%8D%E5%99%A8%E7%9A%84%E6%96%B9%E6%B3%95-1-c11097c23137 https://hackmd.io/@shaoeChen/HJiZtEngG/https%3A%2F%2Fhackmd.io%2Fs%2FSyP4YEnef