Python核心编程笔记————Web 编程:CGI 和 WSGI(二)

本文探讨了CGI中多部分表单提交、文件上传及多值字段处理,并深入讲解了cookie的工作原理及其与文件上传的结合使用。通过具体代码示例,展示了如何在表单提交过程中利用cookie保存用户信息,实现数据持久化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

高级CGI

mulitipart 表单提交和文件上传

. CGI 特别指出只允许两种表单编码:“application/x-www-form-urlencoded”和“multipart/form-dat”。且前者是默认的,因此前者不需要特别指出,但是后者需要明确给出编码:

<FORM enctype="multipart/form-data" ...>

. 表单提交的时候可以使用任意编码,但是在上传文件的时候只能使用multipart编码,通过使用输入类型为文件的方式来完成:

<INPUT type=file name=...>

. 这个指令显示一个空的文本框,同时旁边有个按钮,可以通过该按钮浏览文件目录结构

多值字段

. 常见的处理多值字段的情况是有一系列的复选框,在提交表单的时候,数据以键值对的方式传递给服务器,当提交的不止一个复选框的时候,就会出现多个值对应一个键。在这种情况下,cgi模块会建立一个包含这类实例的列表,可以遍历该列表获得所有值。

cookie

. 可以将其看做web站点服务器要求保存在客户端上的二进制数据。
  从一个页面跳转到另一个页面的方式可以是通过GET请求中的键值对来实现;也可以通过使用隐藏的表单字段,就像是一个标识符,找得到这个标识符就显示这个页面。这些变量和值由服务器托管,因为这些信息必须嵌入到新生成的页面中并返回给客户端。
  另一个可以保持多个页面连续浏览的方式是在客户端保存这些数据,这就是引入cookie的原因。服务器向客户端发送一个请求来保存 cookie,而不必用在返回的 Web 页面中嵌入数据的方法来保持数据。cookie 连接到最初服务器的主域上(这样一个服务器就不能设置或者覆盖其他 Web 站点中的 cookie),并且有一定的存储期限(因此浏览器不会堆满 cookie)。

cookie 和文件上传

. 接下来的例子展示了cookie和文件上传,当第一次登录网页,没有缓存,表单中的输入框都是空的,生成过结果页面后,脚本设置了cookie,缓存在浏览器中,当再次回到表单页面的时候,会自动填入相应的值:

import cgi
from urllib.parse import quote,unquote
import os
import io

class AdvCGI(object):
    header = 'Content-Type: text/html\n\n'
    url = "/cgi-bin/advcgi.py"

    formhtml = '''<html><head><tltle>
    Advanced CGI demon</title></head>
    <body><h2>Advanced CGI Demo Form:</h2>
    <form method = post action = "%s" enctype = "multipart/form-data">
    <h3>my cookie setting</h3>
    <li><code><b>CPPuser = %s</b></code>
    <h3>enter cookie value:<br>
    <input name = cookie value = %s> (<i>optional</i>)</h3>
    <h3>enter your name:<br>
    <input name = person value = %s> (<i>required</i>)</h3>
    <h3>what languages can you program in? (<i>at least one required</i>)</h3>
    %s
    <h3>enter file to upload <small>(max size 4K)</samll></h3>
    <input type = file name = upfile value = "%s" size = 45>
    <p><input type = submit>
    </form></body></html>
    '''

    langset = ('Python','C','C++','Ruby','Java','PHP')
    langitem = '<input type = checkbox name = lang value = "%s" %s>%s\n'

    # 从客户端(浏览器)读取cookie,这个方法只会被showform方法调用
    def getcookie(self):
        if 'HTTP_COOKIE' in os.environ:
            #使用HTTP_COOKIE这个环境变量访问cookie
            cookies = [x.strip() for x in os.environ['HTTP_COOKIE'].split(';')]
            for eachCookie in cookies:
                if len(eachCookie)>6 and eachCookie[:3]=='CPP':
                    tag = eachCookie[3:7]
                    try:
                        self.cookies[tag] = eval(unquote(eachCookie[8:]))
                    except:
                        self.cookies[tag] = unquote(eachCookie[8:])
            if 'info' not in self.cookies:
                self.cookies['info'] = ''
            if 'user' not in self.cookies:
                self.cookies['user'] = ''
        else:
            self.cookies['info'] = self.cookies['user'] = ''

        if self.cookies['info'] != '':
            self.who,langStr,self.fn = self.cookies['info'].split(':')
            self.langs = langStr.split(',')
        else:
            self.who = self.fn = ''
            self.langs = ['Python']

    #用于显示初始界面
    def showForm(self):
        self.getcookie()
        #放置复选框
        langStr = []
        for eachlang in AdvCGI.langset:
            langStr.append(AdvCGI.langitem % (eachlang,'CHECKED' if eachlang in self.langs else '',eachlang))

        if not ('user' in self.cookies and self.cookies['user']):
            cookStatus = '<i>(cookie has not been set yet)</i>'
            userCook = ''
        else:
            userCook = cookStatus = self.cookies['user']
        print('%s%s' % (AdvCGI.header,AdvCGI.formhtml % (AdvCGI.url,cookStatus,
                                                         userCook,self.who,
                                                         ''.join(langStr),self.fn)))

    #用于错误反馈
    errhtml = '''html><head><tltle>
    Advanced CGI demon</title></head>
    <body><h3>Error</h3>
    <b>%s</b><p>
    <form><input type = button value = Back
    ONCLICK = "window.history.back()"></form>
    </body></html>
    '''

    def showErr(self):
        print(AdvCGI.header + AdvCGI.errhtml % self.err)

    #用于生成结果信息页
    reshtml = '''<html><head><tltle>
    Advanced CGI demon</title></head>
    <h3>your cookies value is: <b>%s</b></h3>
    <h3>your name is: <b>%s</b></h3>
    <h3>your can program in the fallowing languages:</h3>
    <ul>%s</ul>
    <h3>your uoloaded file...<br>
    name:<i>%s</i><br>
    contents:</h3>
    <pre>%s</pre>
    Click <a href = "%s"><b>here</b></a>to return to form
    </body></html>
    '''

	#这里设置了cookies,还加上了CPP前缀,和get那里是对应的
    def setcookie(self):
        for eachcookie in self.cookies.keys():
            print('Set-Cookie: CPP%s=%s;path=/' % \
                  (eachcookie,quote(self.cookies[eachcookie])))

    def doResult(self):
        MAXBYTES = 4096
        langlist = ''.join('<li>%s<br>' % eachlang for eachlang in self.langs)
        filedata = self.fp.read(MAXBYTES)
        if len(filedata) == MAXBYTES and f.read():
            filedata = '%s%s' % (filedata,'... <b><i>(file truncated due to size)</i></b>')
        self.fp.close()
        if filedata == '':
            filedata = '<b><i>(file not given or upload error)</i></b>'
        filename = self.fn

        if not ('user' in self.cookies and self.cookies['user']):
            cookStatus = '<i>(cookie has not been set yet)</i>'
            userCook = ''
        else:
            userCook = cookStatus = self.cookies['user']

        self.cookies['info'] = ':'.join((self.who,','.join(self.langs),filename))
        self.setcookie()

        print('%s%s' % (AdvCGI.header,AdvCGI.reshtml % (cookStatus,self.who,langlist,
                                                        filename,filedata,AdvCGI.url)))

    #决定跳转到哪一个页面
    def go(self):
        self.cookies = {}
        self.err = ''
        form = cgi.FieldStorage()
        if not form.keys():
            self.showForm()
            return
        if 'person' in form:
            self.who = form['person'].value.strip().title()
            if self.who == '':
                self.err = 'your name is required.(blank)'
        else:
            self.err = 'your name is required.(miss)'

        self.cookies['user'] = unquote(form['cookie'].value.strip()) if 'cookie' in form else ''

        if 'lang' in form:
            langData = form['lang']
            #isinstance() 函数来判断一个对象是否是一个已知的类型
            if isinstance(langData,list):
                self.langs = [eachLang.value for eachLang in langData]
            else:
                self.langs = [langData.value]
        else:
            self.err = 'at least one language required'

        if 'upfile' in form:
            upfile = form['upfile']
            #or 表示从左到右扫描,返回第一个为真的表达式值,无真值则返回最后一个表达式值。
            self.fn = upfile.filename or ''
            if upfile.file:
                self.fp = upfile.file
            else:
                self.fp = io.StringIO('(no data)')
        else:
            self.fp = io.StringIO('(no file)')
            self.fn = ''

        if not self.err:
            self.doResult()
        else:
            self.showErr()

if __name__ == '__main__':
    page = AdvCGI()
    page.go()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值