Python - CGI編程:初學者指南
你好,未來的Python巫師們!我非常高興能成為你在這個令人興奮的CGI編程與Python結合的旅程中的嚮導。作為一個教了多年計算機科學的人,我告訴你,CGI就像是讓你的網頁應用程式活起來的秘密醬汁。所以,捲起袖子,我們一起深入探討吧!
什麼是CGI?
CGI代表公共網關接口。我知道這聽起來像是滿口胡言,但你可以把它看作是網頁伺服器和Python腳本之間的翻譯員。它就像是一個友好的口譯員,幫助你的伺服器和代碼無縫對接。
CGI使我們能夠創建動態網頁,能夠對用戶輸入做出反應。想像一個網站會根據你的名字來歡迎你,或者顯示個人化的內容 - 這就是CGI的魔法!
網頁瀏覽
在我們深入了解CGI之前,讓我們先簡單看看網頁瀏覽是如何工作的。當你在瀏覽器中輸入URL時,以下事情會發生:
- 你的瀏覽器向網頁伺服器發送請求。
- 網頁伺服器處理請求。
- 伺服器發送回應,通常是HTML頁面的形式。
- 你的瀏覽器渲染這個HTML,顯示你看到的網頁。
當我們想在第三步中生成動態內容時,CGI就派上用場了。
CGI架構圖
這裡有一個簡單的圖表,用來視覺化CGI如何在網頁架構中適用:
+-------------+ HTTP Request +-------------+
| 瀏覽器 | -----------------> | 網頁伺服器 |
| | <----------------- | |
+-------------+ HTTP Response +-------------+
|
| CGI
v
+-------------+
| CGI腳本 |
| (Python) |
+-------------+
網頁伺服器支援與配置
大多數網頁伺服器支援CGI,包括Apache和Nginx。要使用CGI與Python,你需要配置你的伺服器以執行Python腳本。這通常涉及到設置一個特殊的目錄以存放CGI腳本,並告訴伺服器將此目錄中的文件視為可執行。
例如,在Apache中,你可能會在配置中添加如下內容:
<Directory /var/www/cgi-bin>
Options ExecCGI
AddHandler cgi-script .py
</Directory>
這會告訴Apache將/var/www/cgi-bin目錄中的.py文件作為CGI腳本執行。
第一個CGI程序
讓我們來寫第一個CGI程序吧!我們從經典的"Hello, World!"示例開始。在CGI目錄中創建一個名為hello.py
的文件:
#!/usr/bin/env python3
print("Content-Type: text/html")
print()
print("<html>")
print("<head>")
print("<title>Hello World - 第一個CGI程序</title>")
print("</head>")
print("<body>")
print("<h2>Hello World! 這是我的第一個CGI程序</h2>")
print("</body>")
print("</html>")
讓我們來分解一下:
- 第一行告訴伺服器使用Python來執行這個腳本。
-
Content-Type: text/html
是一個HTTP標頭,告訴瀏覽器我們正在發送HTML。 - 空白的
print()
將標頭和響應的正文分開。 - 其餘的就是我們動態生成的HTML。
當你通過網頁瀏覽器訪問這個腳本時,你應該會看到一個顯示"Hello World! 這是我的第一個CGI程序"的頁面。
HTTP標頭
在CGI編程中, 在你的內容之前發送正確的HTTP標頭是至關重要的。 最常見的標頭是Content-Type
,它告訴瀏覽器你正在發送什麼類型的數據。 以下是一些示例:
內容類型 | 描述 |
---|---|
text/html | HTML內容 |
text/plain | 純文本 |
image/jpeg | JPEG圖像 |
application/json | JSON數據 |
永遠記得在內容之前發送適當的Content-Type標頭!
CGI環境變量
CGI腳本可以訪問各種環境變量,它們提供了有關請求的信息。 以下是一個顯示其中一些變量的腳本:
#!/usr/bin/env python3
import os
print("Content-Type: text/html")
print()
print("<html><body>")
print("<h2>環境變量:</h2>")
for param in os.environ.keys():
print(f"<b>%20s</b>: {os.environ[param]}<br>" % (param))
print("</body></html>")
這個腳本將顯示所有可用的環境變量,包括用戶的瀏覽器類型、伺服器名稱等。
GET和POST方法
有兩種主要的方法可以將數據發送到CGI腳本:GET和POST。我們來看看兩者:
GET方法
GET方法將數據作為URL的一部分發送。以下是一個簡單的例子:
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
name = form.getvalue('name', 'World')
print("<html><body>")
print(f"<h2>Hello, {name}!</h2>")
print("</body></html>")
你可以通過URL如http://yourserver.com/cgi-bin/hello.py?name=Alice
訪問此腳本,它將顯示"Hello, Alice!"。
POST方法
POST方法將數據作為HTTP請求的正文發送。它通常用於表單。以下是一個示例:
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
name = form.getvalue('name', 'World')
email = form.getvalue('email', 'Not provided')
print("<html><body>")
print(f"<h2>Hello, {name}!</h2>")
print(f"<p>你的郵箱是:{email}</p>")
print("</body></html>")
這個腳本可以與使用POST方法的HTML表單一起使用。
處理不同的表單元素
CGI可以處理各種表單元素。我們來看看一些例子:
勾選框
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
hobbies = form.getlist('hobby')
print("<html><body>")
print("<h2>你的愛好:</h2>")
for hobby in hobbies:
print(f"<p>{hobby}</p>")
print("</body></html>")
開關按鈕
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
gender = form.getvalue('gender', '未指定')
print("<html><body>")
print(f"<h2>你的性別:{gender}</h2>")
print("</body></html>")
文本區域
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
message = form.getvalue('message', '沒有提供信息')
print("<html><body>")
print("<h2>你的信息:</h2>")
print(f"<p>{message}</p>")
print("</body></html>")
下拉框
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
country = form.getvalue('country', '未選擇')
print("<html><body>")
print(f"<h2>你的國家:{country}</h2>")
print("</body></html>")
在CGI中使用Cookies
Cookies是將小塊數據存儲在客戶端的一種方式。它們用於記憶用戶偏好或維護會話信息。以下是你如何在CGI中處理cookies的方法:
設置Cookies
#!/usr/bin/env python3
import cgi
from http import cookies
import datetime
# 創建一個cookie
c = cookies.SimpleCookie()
c['lastvisit'] = str(datetime.datetime.now())
c['lastvisit']['expires'] = 365 * 24 * 60 * 60 # 一年後過期
print(c) # 這會打印出Set-Cookie標頭
print("Content-Type: text/html")
print()
print("<html><body>")
print("<h2>Cookie設置!</h2>")
print("</body></html>")
檢索Cookies
#!/usr/bin/env python3
import os
from http import cookies
print("Content-Type: text/html")
print()
if 'HTTP_COOKIE' in os.environ:
cookie_string = os.environ.get('HTTP_COOKIE')
c = cookies.SimpleCookie()
c.load(cookie_string)
lastvisit = c.get('lastvisit')
if lastvisit:
print(f"<h2>你的最後訪問是在:{lastvisit.value}</h2>")
else:
print("<h2>這是你第一次訪問!</h2>")
else:
print("<h2>這是你第一次訪問!</h2>")
文件上傳示例
處理文件上傳有點複雜,但以下是一個簡單的例子:
#!/usr/bin/env python3
import cgi, os
import cgitb; cgitb.enable()
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
# 在這裡獲取文件名。
fileitem = form['filename']
# 測試文件是否上傳
if fileitem.filename:
# 從文件名中刪除前面的路徑,避免目錄遍歷攻擊
fn = os.path.basename(fileitem.filename)
open('/tmp/' + fn, 'wb').write(fileitem.file.read())
message = f'文件"{fn}"上傳成功'
else:
message = '沒有文件被上傳'
print(f"""\
<html>
<body>
<p>{message}</p>
</body>
</html>
""")
如何引發“文件下載”對話框?
要觸發文件下載,你需要設置適當的標頭:
#!/usr/bin/env python3
import os
filename = "example.txt" # 這將是你的文件名
filepath = "/path/to/your/file" # 這將是文件的路徑
print("Content-Type: application/octet-stream")
print(f"Content-Disposition: attachment; filename={filename}")
print() # 空行,標頭結束
# 現在發送文件內容
with open(os.path.join(filepath, filename), 'rb') as f:
print(f.read())
這個腳本設置了Content-Type為application/octet-stream
,這告訴瀏覽器下載文件而不是顯示它。Content-Disposition標頭建議下載時的文件名。
以上就是CGI編程與Python的基础知识。請記住,熟練掌握需要多加練習,所以不要害怕實驗這些例子並創建自己的。祝編程愉快,願你的CGI腳本永遠運行平穩!
Credits: Image by storyset