1. 程式人生 > >http伺服器究竟做了什麼(三)

http伺服器究竟做了什麼(三)

本節內容將通過一些示例來說明CGI程式.前面講過CGI程式可以用任何語言編寫,考慮到便捷性,這裡用python來展示CGI程式.

首先搭建伺服器.我這裡用了最輕量級的http伺服器tinyhttp,總共程式碼只有500行左右,後面的伺服器程式碼分析也是基於這個.在他的htdocs裡新增一個test.cgi,寫CGI程式碼.注意,test.cgi指令碼要有可執行的的許可權,否則訪問test.cgi時,將直接讀取裡面的文字,而不是執行該檔案. test.cgi程式碼如下:

#!/usr/bin/python        #注意要新增這行,表示該檔案會被python解析器解析
# -*- coding: UTF-8 -*-
print "Content-type:text/html"
print                               # 空行,告訴伺服器結束頭部
print '<html>'
print '<head>'
print '<meta charset="utf-8">'
print '<title>Hello World - 我的第一個 CGI 程式!</title>'
print '</head>'
print '<body>'
print '<h2>Hello World! 我是第一個CGI程式</h2>'
print '</body>'
print '</html>'

開啟我們的伺服器,訪問/test.cgi,瀏覽器會得到:

Hello World! 我是第一個CGI程式

我做實驗時,第一次沒有顯示,報錯資訊/usr/bin/python^M: bad interpreter: No such file or directory. 是因為cgi文字格式為dos,用vim set ff=unix就可以改過來了.

我們再來梳理一下瀏覽器得到這個結果的過程:

瀏覽器發起請求,伺服器收到請求,轉給CGI程式處理.CGI列印一段簡單的http文字,重定向給伺服器,伺服器返回給瀏覽器,然後我們就看到了結果.

列印環境變數:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import os

print "Content-type:text/html"
print                               # 空行,告訴伺服器結束頭部
print '<html>'
print '<meta charset=\"utf-8\">'
print '<b>環境變數</b><br>'
print '<ul>'

list_env = ['REQUEST_METHOD', 'QUERY_STRING', 'CONTENT_LENGTH', 'CONTENT_TYPE','CONTENT_FILE','PATH_INFO','PATH_TRANSLATED','SCRIPT_NAME']

for key in os.environ.keys():
	if key in list_env:
		print "<li><span style='color:green'>%30s </span> : %s </li>" % (key, os.environ[key])
為了保持簡單,程式中只輸出相關的環境變數.

請求 /test.cgi?name=shonm&age=25 得到的結果為:


我們再來看post的結果,html的頁面程式碼為:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>測試post</title>
</head>
<body>
<form action="/test.cgi" method="post">
	姓名: <input type="text" name="name">  <br />

	年齡: <input type="text" name="age" />
	<input type="submit" value="提交" />
</form>
</body>
</html>

/test.cgi:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import os,cgi

print "Content-type:text/html"
print                               # 空行,告訴伺服器結束頭部
print '<html>'
print '<meta charset=\"utf-8\">'
print '<b>環境變數</b><br>'
print '<ul>'

list_env = ['REQUEST_METHOD', 'QUERY_STRING', 'CONTENT_LENGTH', 
			'CONTENT_TYPE','CONTENT_FILE','PATH_INFO','PATH_TRANSLATED','SCRIPT_NAME']

for key in os.environ.keys():
	if key in list_env:
		print "<li><span style='color:green'>%30s </span> : %s </li>" % (key, os.environ[key])

if os.environ['REQUEST_METHOD'] == 'POST':
	# 建立 FieldStorage 的例項化
	form = cgi.FieldStorage() 

	# 獲取資料
	name = form.getvalue('name')
	age  = form.getvalue('age')
	print '<br> name is %s, age is %s ' %(name, age)

點選提交,得到:


POST請求,在環境變數中沒有關於請求內容的欄位,只有內容的長度,根據這個長度,然後伺服器再次讀取socket獲取內容.上面的內容為:'name=shonm&age=25',和用GET請求(可以改form method = 'get')時QUERY_STRING欄位的內容一致.