C++ CGI Web 编程
C++ 也是可以用来写 Web 应用程序的,在众所周知的大厂 腾讯,据说还有很多 Web 应用程序是用 C++ 写的
CGI
CGI
( Common Gateway Interface
),中文公共网关接口,是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换
CGI
是一种用于外部网关程序与信息服务器 ( 如 HTTP 服务器 ) 对接的接口标准
- 目前的版本是 CGI/1.1,CGI/1.2 版本正在推进中。
WEB 浏览
为了更好的理解 CGI 的作用,让我们点击一个超链接,浏览一个特定的网页或 URL,看看会发生什么
-
浏览器联系上 HTTP Web 服务器,并请求 URL,即文件名
-
Web 服务器将解析 URL,并查找文件名
如果找到请求的文件,Web 服务器会把文件发送回浏览器,否则发送一条错误消息, 表明请求了一个错误的文件
- Web 浏览器从 Web 服务器获取响应,并根据接收到的响应来显示文件或错误消息
以这种方式搭建起来的 HTTP 服务器,不管何时请求目录中的某个文件,HTTP 服务器发送回来的不是该文件,而是以程序形式执行,并把执行产生的输出发送回浏览器显示出来
CGI
是使得应用程序(称为 CGI 程序或 CGI 脚本)能够与 Web 服务器以及客户端进行交互的标准协议
这些 CGI 程序可以用 Python、PERL、Shell、C 或 C++ 等进行编写
CGI 架构图
Web 服务器配置
百度搜索 CGI 服务器,出现的是千篇一律的 Apache,难不成我们开发一个 CGI demo 还要劳师动众的装一个 Apache
所以这里,我们就不用 Apache 了,而是用 Python 自带的 CGI 容器
如果你是 Windows 系统,如果还没装 Python,那么可以访问 Python 3 安装 安装 Python 3
如果你用的是 Linux
系统,比如 Ubuntu
或者 CentOS
等,或者苹果电脑,那么恭喜你,系统已经自带了 Python
然后创建一个目录用来放 CGI 程序,比如 D:/cgi
(Windows) 或者 ~/Downloads/cgi
(苹果电脑) 或者 ~/cgi
(Linux)
打开一个终端 (命令行提示符,windows) 跳转到上面的目录, 然后执行下面的命令
Python 3.x
python -m http.server --cgi 8080
Python 2.x
python2.7 -m CGIHTTPServer 8080
就可以开启 CGI Server 了
然后在浏览器里输入 http://localhost:8080/ 就会出现下面的页面了
C++ CGI Hello World
在上面提到的 CGI 目录下再创建一个目录 cgi-bin
然后在 cgi-bin
目录下创建文件 index.cpp
然后输入下面的内容
/** * file: index.cpp * author: 简单教程(www.twle.cn) * * Copyright © 2015-2065 www.twle.cn. All rights reserved. */ #include <iostream> int main () { std::cout << "Content-type:text/html;charset=utf-8\r\n\r\n"; std::cout << "<!DOCTYPE html>"; std::cout << "<meta charset='utf-8'/>"; std::cout << "<title>Hello www.twle.cn - 我的 第一个 CGI 程序</title>"; std::cout << "<h2>Hello www.twle.cn - 我的 第一个 CGI 程序</h2>"; return 0; }
然后使用下面的命令编译我们的 hello.cpp
g++ -o index.cgi index.cpp
然后使用 chmod 755 index.cgi
设置权限确保文件可执行
打开浏览器,输入 http://localhost:8080/cgi-bin/index
是不是看到了下面的内容
如果你使用的是 Chrome 那么在网页上点击右键,然后选择 显示网页源代码
可以看到如下内容
<!DOCTYPE html> <meta charset='utf-8'/> <title>Hello www.twle.cn - 我的 第一个 CGI 程序</title> <h2>Hello www.twle.cn - 我的 第一个 CGI 程序</h2>
是不是很熟悉,除了下面这行不知道到哪里去了之外,其它的都还在
std::cout << "Content-type:text/html;charset=utf-8\r\n\r\n";
我们来分析下这个 index.cpp
-
主要的代码都是使用
std:cout
将所有的内容输出到标准输出 -
std::cout << "Content-type:text/html;charset=utf-8\r\n\r\n";
这行代码是告诉浏览器,我发送的内容类型是
text/html
也就是网页啦,然后发送的内容使用的是utf-8
编码当浏览器收到这行,就会把收到的内容当作网页来显示
我们把
Content-type:text/html;charset=utf-8
称之为 HTTP 响应头
两个回车换行符
\r\n\r\n
是用来分隔响应头和响应内容的
HTTP 头信息
我们刚介绍了 Content-type:text/html;charset=utf-8
是 HTTP 头信息的组成部分
HTTP 头信息的格式如下
HTTP 字段名称: 字段内容
例如
Content-type: text/html;charset=utf-8
如果有多个 HTTP 头部信息,则相互之间使用一个 \r\n
来分别,就像下面这样
Content-type: text/html;charset=utf-8\r\nExpires:01 Jan 1998 12:00:00 GMT
因为 \r\n
就是回车换行符,所以显示出来就会这样子
Content-type: text/html;charset=utf-8 Expires:01 Jan 1998 12:00:00 GMT
下表列出了一些其它的重要的 HTTP 头信息
头信息 | 描述 |
---|---|
Content-type: | MIME 字符串,定义返回的文件格式 例如 Content-type:text/html;charset=utf-8 |
Expires: Date | 信息变成无效的日期 浏览器使用它来判断一个页面何时需要刷新 日期字符串的格式应为 01 Jan 1998 12:00:00 GMT |
Location: URL | 这个 URL 是指应该返回的 URL,而不是请求的 URL 可以使用它来重定向一个请求到任意的文件 |
Last-modified: Date | 资源的最后修改日期 |
Content-length: N | 要返回的数据的长度,以字节为单位 浏览器使用这个值来表示一个文件的预计下载时间 |
Set-Cookie: string | 设置 cookie |
CGI 环境变量
所有的 CGI 程序都可以访问下列的环境变量
变量名 | 描述 |
---|---|
CONTENT_TYPE | 内容的数据类型。当客户端向服务器发送附加内容时使用。例如,文件上传等功能 |
CONTENT_LENGTH | 查询的信息长度。只对 POST 请求可用 |
HTTP_COOKIE | 以键 & 值对的形式返回设置的 cookies |
HTTP_USER_AGENT | 用户代理请求标头字段,递交用户发起请求的有关信息,包含了浏览器的名称、版本和其他平台性的附加信息 |
PATH_INFO | CGI 脚本的路径 |
QUERY_STRING | 通过 GET 方法发送请求时的 URL 编码信息,包含 URL 中问号后面的参数 |
REMOTE_ADDR | 发出请求的远程主机的 IP 地址。这在日志记录和认证时是非常有用的 |
REMOTE_HOST | 发出请求的主机的完全限定名称。如果此信息不可用,则可以用 REMOTE_ADDR 来获取 IP 地址。 |
REQUEST_METHOD | 用于发出请求的方法。最常见的方法是 GET 和 POST |
SCRIPT_FILENAME | CGI 脚本的完整路径 |
SCRIPT_NAME | CGI 脚本的名称 |
SERVER_NAME | 服务器的主机名或 IP 地址 |
SERVER_SOFTWARE | 服务器上运行的软件的名称和版本 |
我们写一个 CGI 脚本来输出当前的所有 CGI 变量
在 cgi-bin
目录下新建一个文件 env.cpp
然后输入以下内容
/** * file: index.cpp * author: 简单教程(www.twle.cn) * * Copyright © 2015-2065 www.twle.cn. All rights reserved. */ #include <iostream> #include <stdlib.h> #include <string> const std::string ENV[ 24 ] = { "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST", "HTTP_USER_AGENT", "PATH", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN", "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SIGNATURE", "SERVER_SOFTWARE" }; int main () { std::cout << "Content-type:text/html;charset=utf-8\r\n\r\n"; std::cout << "<!DOCTYPE html>"; std::cout << "<title>CGI 环境变量</title>\n"; std::cout << "<table border = \"0\" cellspacing = \"1\">"; for ( int i = 0; i < 24; i++ ) { std::cout << "<tr><td>" << ENV[ i ] << "</td><td>"; // 尝试检索环境变量的值 char *value = getenv( ENV[ i ].c_str() ); if ( value != 0 ){ std::cout << value; } std::cout << "</td></tr>\n"; } std::cout << "</table>\n"; return 0; }
然后使用下面的命令编译我们的 env.cpp
g++ -o env.cgi env.cpp
然后使用 chmod 755 env.cgi
设置权限确保文件可执行
打开浏览器,输入 http://localhost:8080/cgi-bin/env.cgi?id=1&name=2
是不是看到了下面的内容
虽然大部分值都是空,但是对 WEB 开发来说最重要的几个都是有值的