主页
  • 主页
  • 分类
  • 热文
  • 教程
  • 面试
  • 标签
Python

Python 基础

Python 主页
Python 概述
Python 历史
Python 功能
Python 与 C++
Python Hello World
Python 应用领域
Python 解释器及其模式
Python 环境设置
Python 虚拟环境
Python 语法
Python 变量
Python 数据类型
Python 类型转换
Python Unicode 系统
Python 文字
Python 运算符
Python 算术运算符
Python 比较运算符
Python 赋值运算符
Python 逻辑运算符
Python 位运算符
Python 成员运算符
Python 身份运算符
Python 运算符优先级
Python 注释
Python 用户输入
Python 数字
Python 布尔值

Python 控制语句

Python 控制流
Python 决策
Python if 语句
Python if-else 语句
Python 嵌套 if 语句
Python match-case 语句
Python 循环
Python For 循环
Python for-else 循环
Python while 循环
Python break 语句
Python Continue 语句
Python pass 语句
Python 嵌套循环

Python 函数和模块

Python 函数
Python 默认参数
Python 关键字参数
Python 关键字专用参数
Python 位置参数
Python 仅限位置参数
Python 任意或可变长度参数
Python 变量作用域
Python 函数注释
Python 模块
Python 内置函数

Python 字符串

Python 字符串
Python 字符串切片
Python 字符串修改
Python 字符串连接
Python 字符串格式化
Python 转义字符
Python 字符串方法
Python 字符串练习

Python 列表

Python 列表
Python 访问列表项
Python 更改列表项
Python 添加列表项
Python 删除列表项
Python 循环列表
Python 列表推导式
Python 排序列表
Python 复制列表
Python 合并列表
Python 列表方法
Python 列表练习

Python 元组

Python 元组
Python 访问元组项
Python 更新元组
Python 解包元组项
Python 循环元组
Python 合并元组
Python 元组方法
Python 元组练习

Python 集合

Python 集合
Python 访问集合项
Python 添加集合项
Python 删除集合项
Python 循环集合
Python 合并集合
Python 复制集合
Python 集合运算符
Python 集合方法
Python 集合练习

Python 字典

Python 字典
Python 访问字典项
Python 更改字典项
Python 添加字典项
Python 移除字典项
Python 字典视图对象
Python 循环字典
Python 复制字典
Python 嵌套字典
Python 字典方法
Python 字典练习

Python 数组

Python 数组
Python 访问数组项
Python 添加数组项
Python 移除数组项
Python 循环数组
Python 复制数组
Python 反转数组
Python 排序数组
Python 合并数组
Python 数组方法
Python 数组练习

Python 文件处理

Python 文件处理
Python 文件写入
Python 文件读取
Python 重命名和删除文件
Python 目录
Python 文件方法
Python 文件/目录方法
Python OS.Path 方法

Python 面向对象编程

Python OOP 概念
Python 类和对象
Python 类属性
Python 类方法
Python 静态方法
Python 构造函数
Python 访问修饰符
Python 继承
Python 多态
Python 方法重写
Python 方法重载
Python 动态绑定
Python 动态类型
Python 抽象
Python 封装
Python 接口
Python 包
Python 内部类
Python 匿名类和对象
Python 单例类
Python 包装器类
Python 枚举
Python 反射

Python 错误和异常

Python 语法错误
Python 异常处理
Python Try-Except
Python Try-Finally
Python 抛出异常
Python 异常链
Python 嵌套 try
Python 用户定义异常
Python 日志记录
Python 断言
Python 内置异常

Python 多线程

Python 多线程
Python 线程生命周期
Python 创建线程
Python 启动线程
Python 合并线程
Python 命名线程
Python 线程调度
Python 线程池
Python 主线程
Python 线程优先级
Python 守护线程
Python 线程同步

Python 同步

Python 线程间通信
Python 死锁
Python 中断线程

Python 网络

Python 网络编程
Python 套接字编程
Python URL 处理
Python 泛型

Python 杂项

Python Date and Time
Python math模块
Python 迭代器
Python 生成器
Python 闭包
Python 装饰器
Python 递归
Python 正则表达式
Python Pip
Python 数据库访问
Python 弱引用
Python 序列化
Python 模板技术
Python 输出格式化
Python 性能测量
Python 数据压缩
Python 通用网关接口
Python XML 处理
Python 用户界面(GUI)
Python 命令行参数
Python Docstrings
Python JSON
Python 发送电子邮件
Python 进一步扩展
Python 工具/实用程序
Python GUI

Python 高级概念

Python 抽象基类
Python 自定义异常
Python 高阶函数
Python 对象的内部机制
Python 内存管理
Python 元类
Python 元编程
Python 模拟与桩
Python 猴子补丁
Python 信号处理
Python 类型提示
Python 进行自动化
Python Humanize包
Python 上下文管理器
Python 协程
Python 描述符
Python 内存泄漏
Python 不可变数据结构

基础

Python 主页
Python 概述
Python 历史
Python 功能
Python 与 C++
Python Hello World
Python 应用领域
Python 解释器及其模式
Python 环境设置
Python 虚拟环境
Python 语法
Python 变量
Python 数据类型
Python 类型转换
Python Unicode 系统
Python 文字
Python 运算符
Python 算术运算符
Python 比较运算符
Python 赋值运算符
Python 逻辑运算符
Python 位运算符
Python 成员运算符
Python 身份运算符
Python 运算符优先级
Python 注释
Python 用户输入
Python 数字
Python 布尔值

控制语句

Python 控制流
Python 决策
Python if 语句
Python if-else 语句
Python 嵌套 if 语句
Python match-case 语句
Python 循环
Python For 循环
Python for-else 循环
Python while 循环
Python break 语句
Python Continue 语句
Python pass 语句
Python 嵌套循环

函数和模块

Python 函数
Python 默认参数
Python 关键字参数
Python 关键字专用参数
Python 位置参数
Python 仅限位置参数
Python 任意或可变长度参数
Python 变量作用域
Python 函数注释
Python 模块
Python 内置函数

字符串

Python 字符串
Python 字符串切片
Python 字符串修改
Python 字符串连接
Python 字符串格式化
Python 转义字符
Python 字符串方法
Python 字符串练习

列表

Python 列表
Python 访问列表项
Python 更改列表项
Python 添加列表项
Python 删除列表项
Python 循环列表
Python 列表推导式
Python 排序列表
Python 复制列表
Python 合并列表
Python 列表方法
Python 列表练习

元组

Python 元组
Python 访问元组项
Python 更新元组
Python 解包元组项
Python 循环元组
Python 合并元组
Python 元组方法
Python 元组练习

集合

Python 集合
Python 访问集合项
Python 添加集合项
Python 删除集合项
Python 循环集合
Python 合并集合
Python 复制集合
Python 集合运算符
Python 集合方法
Python 集合练习

字典

Python 字典
Python 访问字典项
Python 更改字典项
Python 添加字典项
Python 移除字典项
Python 字典视图对象
Python 循环字典
Python 复制字典
Python 嵌套字典
Python 字典方法
Python 字典练习

数组

Python 数组
Python 访问数组项
Python 添加数组项
Python 移除数组项
Python 循环数组
Python 复制数组
Python 反转数组
Python 排序数组
Python 合并数组
Python 数组方法
Python 数组练习

文件处理

Python 文件处理
Python 文件写入
Python 文件读取
Python 重命名和删除文件
Python 目录
Python 文件方法
Python 文件/目录方法
Python OS.Path 方法

面向对象编程

Python OOP 概念
Python 类和对象
Python 类属性
Python 类方法
Python 静态方法
Python 构造函数
Python 访问修饰符
Python 继承
Python 多态
Python 方法重写
Python 方法重载
Python 动态绑定
Python 动态类型
Python 抽象
Python 封装
Python 接口
Python 包
Python 内部类
Python 匿名类和对象
Python 单例类
Python 包装器类
Python 枚举
Python 反射

错误和异常

Python 语法错误
Python 异常处理
Python Try-Except
Python Try-Finally
Python 抛出异常
Python 异常链
Python 嵌套 try
Python 用户定义异常
Python 日志记录
Python 断言
Python 内置异常

多线程

Python 多线程
Python 线程生命周期
Python 创建线程
Python 启动线程
Python 合并线程
Python 命名线程
Python 线程调度
Python 线程池
Python 主线程
Python 线程优先级
Python 守护线程
Python 线程同步

同步

Python 线程间通信
Python 死锁
Python 中断线程

网络

Python 网络编程
Python 套接字编程
Python URL 处理
Python 泛型

杂项

Python Date and Time
Python math模块
Python 迭代器
Python 生成器
Python 闭包
Python 装饰器
Python 递归
Python 正则表达式
Python Pip
Python 数据库访问
Python 弱引用
Python 序列化
Python 模板技术
Python 输出格式化
Python 性能测量
Python 数据压缩
Python 通用网关接口
Python XML 处理
Python 用户界面(GUI)
Python 命令行参数
Python Docstrings
Python JSON
Python 发送电子邮件
Python 进一步扩展
Python 工具/实用程序
Python GUI

高级概念

Python 抽象基类
Python 自定义异常
Python 高阶函数
Python 对象的内部机制
Python 内存管理
Python 元类
Python 元编程
Python 模拟与桩
Python 猴子补丁
Python 信号处理
Python 类型提示
Python 进行自动化
Python Humanize包
Python 上下文管理器
Python 协程
Python 描述符
Python 内存泄漏
Python 不可变数据结构

Python 通用网关接口


上一章 下一章

通用网关接口(Common Gateway Interface,简称 CGI)是一组标准,定义了 Web 服务器与自定义脚本之间如何交换信息。当前的 CGI 规范由 NCSA 维护。

什么是 CGI?

通用网关接口(Common Gateway Interface,简称 CGI)是一种外部网关程序的标准,用于与诸如 HTTP 服务器之类的信息服务器进行交互。

当前版本是 CGI/1.1 并且 CGI/1.2 正在开发中。

Web 浏览

为了理解 CGI 的概念,让我们来看看当我们点击一个超链接浏览特定网页或 URL 时会发生什么。

浏览器联系 HTTP Web 服务器并请求 URL,即文件名。

Web 服务器解析 URL 并查找文件名。如果找到了该文件就将其发送回浏览器,否则发送错误信息,表明您请求了一个错误的文件。

Web 浏览器接收来自 Web 服务器的响应并显示接收到的文件或错误信息。

然而,有可能设置 HTTP 服务器,使得每当请求某个目录中的文件时,该文件不是被发回,而是作为程序执行,该程序的输出被发回供浏览器显示。这个功能被称为通用网关接口或 CGI,而这些程序被称为 CGI 脚本。这些 CGI 程序可以是 Python 脚本、PERL 脚本、Shell 脚本、C 或 C++ 程序等。

CGI 架构图

Cgi Architecture Diagram

Web 服务器支持和配置

在继续进行 CGI 编程之前,请确保您的 Web 服务器支持 CGI 并且已配置以处理 CGI 程序。所有需要由 HTTP 服务器执行的 CGI 程序都保存在一个预先配置好的目录中。这个目录称为 CGI 目录,并且按照惯例命名为 /var/www/cgi-bin。按照惯例,CGI 文件的扩展名为 .cgi,但您也可以使用 .py 扩展名。

默认情况下,Linux 服务器被配置为仅运行位于 /var/www/cgi-bin 目录中的脚本。如果您想指定其他目录来运行您的 CGI 脚本,请在 httpd.conf 文件中注释掉以下行:

<Directory "/var/www/cgi-bin">
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all
</Directory>

<Directory "/var/www/cgi-bin">
Options All
</Directory>

对于 Apache 服务器,还需添加以下行以便将其视为 CGI 脚本:

AddHandler cgi-script .py

这里假设您已经成功启动了 Web 服务器并且能够运行其他 CGI 程序,如 Perl 或 Shell 等。

第一个 CGI 程序

这里是一个简单的链接,指向一个名为 hello.py 的 CGI 脚本。该文件保存在 /var/www/cgi-bin 目录中,内容如下。在运行您的 CGI 程序之前,请确保使用 UNIX 命令 chmod 755 hello.py 更改文件模式以使其可执行。

print ("Content-type:text/html\r\n\r\n")
print ('<html>')
print ('<head>')
print ('<title>Hello Word - First CGI Program</title>')
print ('</head>')
print ('<body>')
print ('<h2>Hello Word! This is my first CGI program</h2>')
print ('</body>')
print ('</html>')

注意:脚本的第一行必须是 Python 可执行文件的路径。这在 Python 程序中看起来像一条注释,但实际上称为 shebang 行。

在 Linux 中,应为 #!/usr/bin/python3。

在 Windows 中,应为 #!c:/python311/python.exe。

在浏览器中输入以下 URL:

http://localhost/cgi-bin/hello.py

输出将是:Hello Word! This is my first CGI program

此 hello.py 脚本是一个简单的 Python 脚本,它将输出写入到标准输出流,即屏幕。有一个重要的额外功能是输出的第一行 Content-type:text/html\r\n\r\n。这一行被发送回浏览器,并指定了浏览器屏幕上显示的内容类型。

至此,您应该已经理解了 CGI 的基本概念,并且可以使用 Python 编写许多复杂的 CGI 程序。此脚本还可以与其他外部系统交互以交换信息,例如关系数据库管理系统(RDBMS)。

HTTP 头部

Content-type:text/html\r\n\r\n 是发送到浏览器的一部分 HTTP 头部,用来让浏览器理解内容。所有 HTTP 头部的格式如下:

HTTP 字段名称: 字段内容

例如:

Content-type: text/html\r\n\r\n

还有几个其他重要的 HTTP 头部,在您的 CGI 编程中会经常用到。

序号 头部 描述
1 Content-type: 一个 MIME 字符串,定义了返回文件的格式。例如 Content-type:text/html
2 Expires: Date 信息变得无效的日期。它由浏览器用来决定何时需要刷新页面。有效的日期字符串格式为 01 Jan 1998 12:00:00 GMT
3 Location: URL 返回的 URL 而不是请求的 URL。您可以使用此字段将请求重定向到任何文件。
4 Last-modified: Date 资源最后修改的日期。
5 Content-length: N 返回数据的长度(以字节为单位)。浏览器使用此值报告文件下载的预计时间。
6 Set-Cookie: String 设置通过字符串传递的 cookie

CGI 环境变量

所有 CGI 程序都可以访问以下环境变量。这些变量在编写任何 CGI 程序时起着重要作用。

序号 变量名称 描述
1 CONTENT_TYPE 内容的数据类型。当客户端向服务器发送附加内容时使用。例如文件上传。
2 CONTENT_LENGTH 查询信息的长度。仅适用于 POST 请求。
3 HTTP_COOKIE 返回以键值对形式设置的 cookie。
4 HTTP_USER_AGENT 包含有关发起请求的用户代理的信息的 User-Agent 请求头字段。这是浏览器的名字。
5 PATH_INFO CGI 脚本的路径。
6 QUERY_STRING 使用 GET 方法请求时发送的 URL 编码的信息。
7 REMOTE_ADDR 发出请求的远程主机的 IP 地址。这对于记录或身份验证很有用。
8 REMOTE_HOST 发出请求的主机的完全限定域名。如果没有此信息,则可以使用 REMOTE_ADDR 获取 IP 地址。
9 REQUEST_METHOD 发出请求的方法。最常用的方法是 GET 和 POST。
10 SCRIPT_FILENAME CGI 脚本的完整路径。
11 SCRIPT_NAME CGI 脚本的名称。
12 SERVER_NAME 服务器的主机名或 IP 地址
13 SERVER_SOFTWARE 服务器正在运行的软件的名称和版本。

下面是一个小的 CGI 程序,用来列出所有的 CGI 变量。点击此链接查看结果 Get Environment

import os

print ("Content-type: text/html\r\n\r\n")
print ("<font size=+1>Environment</font><br>")
for param in os.environ.keys():
   print ("<b>%20s</b>: %s<br>" % (param, os.environ[param]))

GET 和 POST 方法

您可能会遇到很多情况,需要从浏览器向 Web 服务器,最终到您的 CGI 程序传递一些信息。浏览器最常使用两种方法传递此信息到 Web 服务器。这两种方法是 GET 方法和 POST 方法。

使用 GET 方法传递信息

GET 方法将编码后的用户信息附加到页面请求上。页面和编码信息由 ? 字符分隔如下:

http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2

GET 方法是默认的方法,用于从浏览器向 Web 服务器传递信息,并且会产生一个长字符串,出现在浏览器的地址栏中。

如果需要传递密码或其他敏感信息,请勿使用 GET 方法。

GET 方法有大小限制:请求字符串只能发送 1024 个字符。

GET 方法通过 QUERY_STRING 头部发送信息,并且可以通过 QUERY_STRING 环境变量在您的 CGI 程序中访问。

简单 URL 示例:GET 方法

这是一个简单的 URL,它通过 GET 方法将两个值传递给 hello_get.py 程序。

/cgi-bin/hello_get.py?first_name=Malhar&last_name=Lathkar

下面是处理浏览器输入的 hello_get.py 脚本。我们将使用 cgi 模块,这使得访问传递的信息变得非常容易。

# 导入 CGI 处理模块
import cgi, cgitb

# 创建 FieldStorage 的实例
form = cgi.FieldStorage()

# 获取数据
first_name = form.getvalue('first_name')
last_name = form.getvalue('last_name')

print ("Content-type:text/html")
print()
print ("<html>")
print ('<head>')
print ("<title>Hello - Second CGI Program</title>")
print ('</head>')
print ('<body>')
print ("<h2>Hello %s %s</h2>" % (first_name, last_name))
print ('</body>')
print ('</html>')

这会产生以下结果:

Hello Malhar Lathkar

简单表单示例:GET 方法

这个例子使用 HTML 表单和提交按钮来传递两个值。我们使用相同的 CGI 脚本 hello_get.py 来处理这个输入。

<form action = "/cgi-bin/hello_get.py" method = "get">
   名字: <input type = "text" name = "first_name">  <br />
   姓氏: <input type = "text" name = "last_name" />
   <input type = "submit" value = "提交" />
</form>

以下是上述表单的实际输出,你输入名字和姓氏然后点击提交按钮来看结果。

名字:

姓氏:

使用 POST 方法传递信息

通常更可靠的方法是使用 POST 方法将信息传递给 CGI 程序。这将信息打包成与 GET 方法相同的方式,但是它不是作为 URL 后面的一个文本字符串发送,而是作为一个单独的消息发送。这个消息以标准输入的形式进入 CGI 脚本。

以下是同一个 hello_get.py 脚本,它可以处理 GET 以及 POST 方法。

# 导入 CGI 处理模块
import cgi, cgitb 

# 创建 FieldStorage 实例
form = cgi.FieldStorage() 

# 从字段获取数据
first_name = form.getvalue('first_name')
last_name  = form.getvalue('last_name')

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"

让我们再次采用上面的例子,使用 HTML 表单和提交按钮来传递两个值。我们使用相同的 CGI 脚本 hello_get.py 来处理这个输入。

<form action = "/cgi-bin/hello_get.py" method = "post">
名字: <input type = "text" name = "first_name"><br />
姓氏: <input type = "text" name = "last_name" />

<input type = "submit" value = "提交" />
</form>

以下是上述表单的实际输出。你输入名字和姓氏然后点击提交按钮来看结果。

名字:

姓氏:

将复选框数据传递给 CGI 程序

当需要选择多个选项时,使用复选框。

以下是包含两个复选框的表单的示例 HTML 代码:

<form action = "/cgi-bin/checkbox.cgi" method = "POST" target = "_blank">
   <input type = "checkbox" name = "maths" value = "on" /> 数学
   <input type = "checkbox" name = "physics" value = "on" /> 物理
   <input type = "submit" value = "选择科目" />
</form>

该代码的结果如下表单:

数学 物理

以下是 checkbox.cgi 脚本来处理浏览器为复选框按钮提供的输入。

# 导入 CGI 处理模块
import cgi, cgitb 

# 创建 FieldStorage 实例
form = cgi.FieldStorage() 

# 从字段获取数据
if form.getvalue('maths'):
   math_flag = "ON"
else:
   math_flag = "OFF"

if form.getvalue('physics'):
   physics_flag = "ON"
else:
   physics_flag = "OFF"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>复选框 - 第三个 CGI 程序</title>"
print "</head>"
print "<body>"
print "<h2>复选框数学是 : %s</h2>" % math_flag
print "<h2>复选框物理是 : %s</h2>" % physics_flag
print "</body>"
print "</html>"

将单选按钮数据传递给 CGI 程序

当只需要选择一个选项时,使用单选按钮。

以下是包含两个单选按钮的表单的示例 HTML 代码:

<form action = "/cgi-bin/radiobutton.py" method = "post" target = "_blank">
   <input type = "radio" name = "subject" value = "maths" /> 数学
   <input type = "radio" name = "subject" value = "physics" /> 物理
   <input type = "submit" value = "选择科目" />
</form>

该代码的结果如下表单:

数学 物理

以下是 radiobutton.py 脚本来处理浏览器为单选按钮提供的输入:

# 导入 CGI 处理模块
import cgi, cgitb 

# 创建 FieldStorage 实例
form = cgi.FieldStorage() 

# 从字段获取数据
if form.getvalue('subject'):
   subject = form.getvalue('subject')
else:
   subject = "未设置"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>单选按钮 - 第四个 CGI 程序</title>"
print "</head>"
print "<body>"
print "<h2>选择的科目是 %s</h2>" % subject
print "</body>"
print "</html>"

将文本区域数据传递给 CGI 程序

当需要传递多行文本给 CGI 程序时,使用 <textarea> 元素。

以下是包含一个文本区域框的表单的示例 HTML 代码:

<form action = "/cgi-bin/textarea.py" method = "post" target = "_blank">
   <textarea name = "textcontent" cols = "40" rows = "4">
      在这里输入你的文字...
   </textarea>
   <input type = "submit" value = "提交" />
</form>

以下是上述代码产生的表单:

在这里输入你的文字...

以下是 textarea.py 脚本来处理浏览器提供的输入:

# 导入 CGI 处理模块
import cgi, cgitb 

# 创建 FieldStorage 实例
form = cgi.FieldStorage() 

# 从字段获取数据
if form.getvalue('textcontent'):
   text_content = form.getvalue('textcontent')
else:
   text_content = "未输入"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>";
print "<title>文本区域 - 第五个 CGI 程序</title>"
print "</head>"
print "<body>"
print "<h2>输入的文本内容是 %s</h2>" % text_content
print "</body>"

将下拉框数据传递给 CGI 程序

当有许多选项可供选择,但只会选择一到两个时,使用下拉框。

以下是包含一个下拉框的表单的示例 HTML 代码:

<form action = "/cgi-bin/dropdown.py" method = "post" target = "_blank">
   <select name = "dropdown">
      <option value = "Maths" selected>数学</option>
      <option value = "Physics">物理</option>
   </select>
   <input type = "submit" value = "提交"/>
</form>

以下是该代码产生的表单:

数学

以下是 dropdown.py 脚本来处理浏览器提供的输入:

# 导入 CGI 处理模块
import cgi, cgitb 

# 创建 FieldStorage 实例
form = cgi.FieldStorage() 

# 从字段获取数据
if form.getvalue('dropdown'):
   subject = form.getvalue('dropdown')
else:
   subject = "未输入"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>下拉框 - 第六个 CGI 程序</title>"
print "</head>"
print "<body>"
print "<h2>选择的科目是 %s</h2>" % subject
print "</body>"
print "</html>"

在 CGI 中使用 Cookie

HTTP 协议是一个无状态协议。对于商业网站来说,保持不同页面之间的会话信息是很必要的。例如,一个用户注册过程需要完成多个页面。如何在所有网页中维持用户的会话信息?

在许多情况下,使用 Cookie 是记住和跟踪偏好、购买、佣金和其他所需信息的最有效的方法,以提供更好的访客体验或站点统计。

它是如何工作的?

您的服务器以 Cookie 的形式将一些数据发送到访客的浏览器。浏览器可能接受该 Cookie。如果它接受了,Cookie 就会被存储为访客硬盘上的纯文本记录。现在,当访客到达您网站的另一个页面时,Cookie 就可用以检索。一旦检索,您的服务器就知道/记住了存储的内容。

Cookie 是一个包含五个变长字段的纯文本数据记录:

  • 过期日期 - Cookie 将过期的日期。如果为空,Cookie 将在访客关闭浏览器时过期。
  • 域 - 您网站的域名。
  • 路径 - 设置 Cookie 的目录或网页的路径。如果希望从任何目录或页面检索 Cookie,则可以为空。
  • 安全 - 如果该字段包含单词 "secure",则只有安全服务器才能检索 Cookie。如果该字段为空,则不存在此类限制。
  • 名称 = 值 - Cookie 以键值对的形式设置和检索。

设置 Cookie

将 Cookie 发送到浏览器是非常简单的。这些 Cookie 是在 Content-type 字段之前的 HTTP 头部一起发送的。假设你想将 UserID 和 Password 设置为 Cookie。设置 Cookie 如下:

print "Set-Cookie:UserID = XYZ;\r\n"
print "Set-Cookie:Password = XYZ123;\r\n"
print "Set-Cookie:Expires = Tuesday, 31-Dec-2007 23:12:40 GMT;\r\n"
print "Set-Cookie:Domain = www.tutorialspoint.com;\r\n"
print "Set-Cookie:Path = /perl;\n"
print "Content-type:text/html\r\n\r\n"
...........HTML 内容的其余部分.......

从这个例子你应该明白如何设置 Cookie。我们使用 Set-Cookie HTTP 头部来设置 Cookie。

设置 Cookie 属性如过期日期、域和路径是可选的。值得注意的是 Cookie 必须在发送 "Content-type:text/html\r\n\r\n" 魔术行之前设置。

检索 Cookie

检索所有设置的 Cookie 非常简单。Cookie 存储在 CGI 环境变量 HTTP_COOKIE 中,并具有以下形式:

key1 = value1;key2 = value2;key3 = value3....

以下是检索 Cookie 的示例。

# 导入 CGI 处理模块
from os import environ
import cgi, cgitb

if 'HTTP_COOKIE' in environ:
   for cookie in [x.strip() for x in environ['HTTP_COOKIE'].split(';')]:
      (key, value) = cookie.split('=');
      if key == "UserID":
         user_id = value

      if key == "Password":
         password = value

print "用户 ID  = %s" % user_id
print "密码 = %s" % password

该脚本设置的 Cookie 会产生以下结果:

用户 ID = XYZ
密码 = XYZ123

文件上传示例

为了上传一个文件,HTML 表单必须将 enctype 属性设置为 multipart/form-data。带有 file 类型的 input 标签创建了一个“浏览”按钮。

<html>
   <body>
      <form enctype = "multipart/form-data" action = "save_file.py" method = "post">
      <p>文件: <input type = "file" name = "filename" /></p>
      <p><input type = "submit" value = "上传" /></p>
      </form>
   </body>
</html>

该代码产生的表单如下:

文件: 未选择任何文件

上面的例子是故意禁用的,以防止人们向我们的服务器上传文件,但是你可以尝试在自己的服务器上运行上面的代码。

以下是处理文件上传的脚本 save_file.py:

import cgi, os
import cgitb; cgitb.enable()

form = cgi.FieldStorage()

# 在这里获取文件名。
fileitem = form['filename']

# 测试文件是否已上传
if fileitem.filename:
   # 从文件名中剥离路径以避免目录遍历攻击
   fn = os.path.basename(fileitem.filename)
   open('/tmp/' + fn, 'wb').write(fileitem.file.read())

   message = '文件 "' + fn + '" 成功上传'
   
else:
   message = '没有文件被上传'
   
print """\
Content-Type: text/html\n
<html>
   <body>
      <p>%s</p>
   </body>
</html>
"""
 % (message,)

如果你在 Unix/Linux 上运行上述脚本,那么你需要替换文件分隔符如下,否则在 Windows 机器上上述 open() 语句应该可以正常工作。

fn = os.path.basename(fileitem.filename.replace("\\", "/" ))

如何弹出“文件下载”对话框?

有时,你可能希望给用户提供一个选项,即用户点击链接后会弹出一个“文件下载”对话框而不是显示实际内容。这非常简单,可以通过 HTTP 头实现。这个 HTTP 头与前面章节提到的头部不同。

例如,如果你想让一个名为 FileName 的文件可以从给定链接下载,其语法如下:

# HTTP 头
print "Content-Type:application/octet-stream; name = \"FileName\"\r\n";
print "Content-Disposition: attachment; filename = \"FileName\"\r\n\n";

# 实际文件内容将放在这里。
fo = open("foo.txt", "rb")

str = fo.read();
print str

# 关闭打开的文件
fo.close()

以上代码展示了如何设置 HTTP 头来提示用户下载文件而非直接展示文件内容。注意替换 FileName 为你实际要下载的文件名,并确保文件路径正确。

上一章 下一章
阅读号二维码

关注阅读号

联系二维码

联系我们

© 2024 Yoagoa. All rights reserved.

粤ICP备18007391号

站点地图