python實現基於CGI的Web應用

本文用一個「網上書店」的web應用示例,簡要介紹如何用Python實現基於CGI標準的Web應用,介紹python的cgi模塊、cigtb模塊對編寫CGI腳本提供的支持。
 
CGI簡介
CGI  Common Gateway Interface (通用網關接口),是一個Internet標準,容許Web服務器運行一個服務器端程序,稱爲CGI腳本。通常的,CGI腳本都放在一個名爲cgi-bin的特殊文件夾內,這樣web服務器就知道到哪裏查找cgi腳本。
 
CGI Architecture Diagram
When a request arrives, HTTP server execute  a program, and whatever that program outputs is sent back for your browser to display. This function is called the Common Gateway Interface or CGI, and the programs are called CGI scripts. These CGI programs can be a Python Script, PERL Script, Shell Script, C or C++ program etc.
 
 
「網上書店」Web應用目錄結構
(操做系統:win7;python版本:3.3)
BookWebApp|
        |cgi-bin
       ------|book_detail_view.py
       ------|book_list_view.py
       ------|template
          ----|yate.py
       ------|mode
          ----|Book.by
       ------|service
          ----|book_service.py
      |resource
      ------- |books.png
      |book.txt
      |index.html
      |run_server.py
 
一、Web服務器
全部的Web應用都要在Web服務器上運行,實際上全部的web服務器都支持CGI,不管是Apache、IIS、nginx、Lighttpd仍是其餘服務器,它們都支持用python編寫的cgi腳本。這些web服務器都比較強大,這裏咱們使用python自帶的簡單的web服務器,這個web服務器包含在http.server庫模塊中。
 
run_server.py:
運行此程序,即啓動此web應用。
from http.server import HTTPServer, CGIHTTPRequestHandler

port = 8081

httpd = HTTPServer(('', port), CGIHTTPRequestHandler)
print("Starting simple_httpd on port: " + str(httpd.server_port))
httpd.serve_forever()

二、index.htmlhtml

首頁;URL: 「http://localhost:8081/cgi-bin/book_list_view.py」 將調用 cgi-bin文件夾下的book_list_view.pypython

<html>
<head>
<title>BookStore</title>
</head>
<body>
<h1>Welcome to My Book Store.</h1>
<img src="resource/books.png">
<h3>
please choose your favorite book, click <a href="cgi-bin/book_list_view.py">here</a>.
</h3>
<p>
<strong> Enjoy!</strong>
</p>
</body>
</html>

三、book_list_view.pynginx

圖書清單頁面。用戶選擇要查看的圖書,提交表單,而後調動圖書詳細界面。git

#Python標準庫中定義的CGI跟蹤模塊:cgibt
import cgitb
cgitb.enable()
#啓用這個模塊時,會在web瀏覽器上顯示詳細的錯誤信息。enable()函數打開CGI跟蹤
#CGI腳本產生一個異常時,Python會將消息顯示在stderr(標準輸出)上。CGI機制會忽略這個輸出,由於它想要的只是CGI的標準輸出(stdout)

import template.yate as yate
import service.book_service as book_service

#CGI標準指出,服務器端程序(CGI腳本)生成的任何輸出都將會由Web服務器捕獲,併發送到等待的web瀏覽器。具體來講,會捕獲發送到Stdout(標準輸出)的全部內容

#
一個CGI腳本由2部分組成, 第一部分輸出 Response Headers, 第二部分輸出常規的html.
print("Content-type:text/html\n")#Response Headers
#網頁內容:有html標籤組成的文本
print('<html>')
print('<head>')
print('<title>Book List</title>')
print('</head>')
print('<body>')
print('<h2>Book List:</h2>')
print(yate.start_form('book_detail_view.py'))
book_dict=book_service.get_book_dict()
for book_name in book_dict:
    print(yate.radio_button('bookname',book_dict[book_name].name))
print(yate.end_form('detail'))
print(yate.link("/index.html",'Home'))
print('</body>')
print('</html>')

四、yate.pyweb

自定義的簡單模板,用於快捷生成html瀏覽器

def start_form(the_url, form_type="POST"):
    return('<form action="' + the_url + '" method="' + form_type + '">')

def end_form(submit_msg="Submit"):
    return('<input type=submit value="' + submit_msg + '"></form>')

def radio_button(rb_name, rb_value):
    return('<input type="radio" name="' + rb_name +
                             '" value="' + rb_value + '"> ' + rb_value + '<br />')

def u_list(items):
    u_string = '<ul>'
    for item in items:
        u_string += '<li>' + item + '</li>'
    u_string += '</ul>'
    return(u_string)

def header(header_text, header_level=2):
    return('<h' + str(header_level) + '>' + header_text +
           '</h' + str(header_level) + '>')
def para(para_text):
    return('<p>' + para_text + '</p>') 

def link(the_link,value):
    link_string = '<a href="' + the_link + '">' + value + '</a>'
    return(link_string)

五、book_detail_view.py服務器

圖書詳細頁面併發

import cgitb
cgitb.enable()

import cgi
import template.yate as yate
import service.book_service as book_service
import template.yate as yate

#使用cig.FieldStorage() 訪問web請求發送給web服務器的數據,這些數據爲一個Python字典 form_data = cgi.FieldStorage() print("Content-type:text/html\n")
print('<html>')
print('<head>')
print('<title>Book List</title>')
print('</head>')
print('<body>')
print(yate.header('Book Detail:'))
try:
   book_name = form_data['bookname'].value
   book_dict=book_service.get_book_dict()
   book=book_dict[book_name]
   print(book.get_html)
except KeyError as kerr:
   print(yate.para('please choose a book...'))
print(yate.link("/index.html",'Home'))
print(yate.link("/cgi-bin/book_list_view.py",'Book List'))
print('</body>')
print('</html>')

六、Book.py函數

圖書類測試

from template import yate

class Book:
    def __init__(self,name,author,price):
        self.name=name
        self.author=author
        self.price=price
    
    @property
    def get_html(self):
        html_str=''
        html_str+=yate.header('BookName:',4)+yate.para(self.name)
        html_str+=yate.header('Author:',4)+yate.para(self.author)
        html_str+=yate.header('Price:',4)+yate.para(self.price)
        return(html_str)

七、book_service.py

圖書業務邏輯類

from model.Book import Book

def get_book_dict():
    book_dict={}
    try:
        with open('book.txt','r') as book_file:
            for each_line in book_file:
                book=parse(each_line)
                book_dict[book.name]=book
    except IOError as ioerr:
        print("IOErr:",ioerr)
    return(book_dict)
    

def parse(book_info):
    (name,author,price)=book_info.split(';')
    book=Book(name,author,price)
    return(book)

八、book.txt

待顯示的圖書信息(書名;做者;價格)

The Linux Programming Interface: A Linux and UNIX System Prog;Michael Kerrisk;$123.01
HTML5 and CSS3, Illustrated Complete (Illustrated Series);Jonathan Meersman Sasha Vodnik;$32.23
Understanding the Linux Kernel;Daniel P. Bovet Marco Cesati;$45.88
Getting Real;Jason Fried, Heinemeier David Hansson, Matthew Linderman;$87.99

 
測試結果
運行run_server.py,瀏覽器訪問: http://localhost:8081/
控制檯會監控請求的信息:
 
點擊「here」,查看圖書清單,即書名列表
 
選擇書名,點擊「detail」提交表單,返回該書的詳細信息:書名、做者、價格
 
 
  (轉載請註明出處 ^.^)
相關文章
相關標籤/搜索