• C++ Web 编程


    C++ Web 编程

    什么是 CGI

    • 公共网关接口(CGI),是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的。
    • CGI 规范目前是由 NCSA 维护的,NCSA 定义 CGI 如下:
    • 公共网关接口(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 架构图

    下图演示了 CGI 的架构:

    Web 服务器配置

    在您进行 CGI 编程之前,请确保您的 Web 服务器支持 CGI,并已配置成可以处理 CGI 程序。所有由 HTTP 服务器执行的 CGI 程序,都必须在预配置的目录中。该目录称为 CGI 目录,按照惯例命名为 /var/www/cgi-bin。虽然 CGI 文件是 C++ 可执行文件,但是按照惯例它的扩展名是 .cgi

    默认情况下,Apache Web 服务器会配置在 /var/www/cgi-bin 中运行 CGI 程序。如果您想指定其他目录来运行 CGI 脚本,您可以在 httpd.conf 文件中修改以下部分:

    
       AllowOverride None
       Options ExecCGI
       Order allow,deny
       Allow from all
    
     
    
    Options All
    

    在这里,我们假设已经配置好 Web 服务器并能成功运行,你可以运行任意的 CGI 程序,比如 Perl 或 Shell 等。

    第一个 CGI 程序

    请看下面的 C++ 程序:

    实例

    1. #include
    2. using namespace std;
    3. int main ()
    4. {
    5. cout << "Content-type:text/html\r\n\r\n";
    6. cout << "\n";
    7. cout << "\n";
    8. cout << "Hello World - 第一个 CGI 程序\n";
    9. cout << "\n";
    10. cout << "\n";
    11. cout << "

      Hello World! 这是我的第一个 CGI 程序

      \n"
      ;
    12. cout << "\n";
    13. cout << "\n";
    14. return 0;
    15. }

    编译上面的代码,把可执行文件命名为 cplusplus.cgi,并把这个文件保存在 /var/www/cgi-bin 目录中。在运行 CGI 程序之前,请使用 chmod 755 cplusplus.cgi UNIX 命令来修改文件模式,确保文件可执行。访问可执行文件,您会看到下面的输出:

    Hello World! 这是我的第一个 CGI 程序

    上面的 C++ 程序是一个简单的程序,把它的输出写在 STDOUT 文件上,即显示在屏幕上。在这里,值得注意一点,第一行输出 Content-type:text/html\r\n\r\n。这一行发送回浏览器,并指定要显示在浏览器窗口上的内容类型。您必须理解 CGI 的基本概念,这样才能进一步使用 Python 编写更多复杂的 CGI 程序。C++ CGI 程序可以与任何其他外部的系统(如 RDBMS)进行交互。

    HTTP 头信息

    行 Content-type:text/html\r\n\r\n 是 HTTP 头信息的组成部分,它被发送到浏览器,以便更好地理解页面内容。HTTP 头信息的形式如下:

    HTTP 字段名称: 字段内容
     
    例如
    Content-type: text/html\r\n\r\n

    还有一些其他的重要的 HTTP 头信息,这些在您的 CGI 编程中都会经常被用到。

    头信息描述
    Content-type:MIME 字符串,定义返回的文件格式。例如 Content-type:text/html。
    Expires: Date信息变成无效的日期。浏览器使用它来判断一个页面何时需要刷新。一个有效的日期字符串的格式应为 01 Jan 1998 12:00:00 GMT。
    Location: URL这个 URL 是指应该返回的 URL,而不是请求的 URL。你可以使用它来重定向一个请求到任意的文件。
    Last-modified: Date资源的最后修改日期。
    Content-length: N要返回的数据的长度,以字节为单位。浏览器使用这个值来表示一个文件的预计下载时间。
    Set-Cookie: String通过 string 设置 cookie。

    CGI 环境变量

    所有的 CGI 程序都可以访问下列的环境变量。这些变量在编写 CGI 程序时扮演了非常重要的角色。

    变量名描述
    CONTENT_TYPE内容的数据类型。当客户端向服务器发送附加内容时使用。例如,文件上传等功能。
    CONTENT_LENGTH查询的信息长度。只对 POST 请求可用。
    HTTP_COOKIE以键 & 值对的形式返回设置的 cookies。
    HTTP_USER_AGENT用户代理请求标头字段,递交用户发起请求的有关信息,包含了浏览器的名称、版本和其他平台性的附加信息。
    PATH_INFOCGI 脚本的路径。
    QUERY_STRING通过 GET 方法发送请求时的 URL 编码信息,包含 URL 中问号后面的参数。
    REMOTE_ADDR发出请求的远程主机的 IP 地址。这在日志记录和认证时是非常有用的。
    REMOTE_HOST发出请求的主机的完全限定名称。如果此信息不可用,则可以用 REMOTE_ADDR 来获取 IP 地址。
    REQUEST_METHOD用于发出请求的方法。最常见的方法是 GET 和 POST。
    SCRIPT_FILENAMECGI 脚本的完整路径。
    SCRIPT_NAMECGI 脚本的名称。
    SERVER_NAME服务器的主机名或 IP 地址。
    SERVER_SOFTWARE服务器上运行的软件的名称和版本。

    下面的 CGI 程序列出了所有的 CGI 变量。

    实例

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. const string ENV[ 24 ] = {
    6. "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",
    7. "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",
    8. "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION",
    9. "HTTP_HOST", "HTTP_USER_AGENT", "PATH",
    10. "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",
    11. "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME",
    12. "SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN",
    13. "SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL",
    14. "SERVER_SIGNATURE","SERVER_SOFTWARE" };
    15. int main ()
    16. {
    17. cout << "Content-type:text/html\r\n\r\n";
    18. cout << "\n";
    19. cout << "\n";
    20. cout << "CGI 环境变量\n";
    21. cout << "\n";
    22. cout << "\n";
    23. cout << "";
    24. for ( int i = 0; i < 24; i++ )
    25. {
    26. cout << "
    27. \n";
    28. }
    29. cout << "
    30. " << ENV[ i ] << "";
    31. // 尝试检索环境变量的值
    32. char *value = getenv( ENV[ i ].c_str() );
    33. if ( value != 0 ){
    34. cout << value;
    35. }else{
    36. cout << "环境变量不存在。";
    37. }
    38. cout << "
    39. <\n"
      ;
    40. cout << "\n";
    41. cout << "\n";
    42. return 0;
    43. }

    C++ CGI 库

    在真实的实例中,您需要通过 CGI 程序执行许多操作。这里有一个专为 C++ 程序而编写的 CGI 库,我们可以从 ftp://ftp.gnu.org/gnu/cgicc/ 上下载这个 CGI 库,并按照下面的步骤安装库:

    $ tar xzf cgicc-X.X.X.tar.gz 
    $ cd cgicc-X.X.X/ 
    $ ./configure --prefix=/usr 
    $ make
    $ make install

    注意:libcgicc.so 和 libcgicc.a 库会被安装到/usr/lib目录下,需执行拷贝命令:

    $ sudo cp /usr/lib/libcgicc.* /usr/lib64/

    才能使 CGI 程序自动找到 libcgicc.so 动态链接库。

    您可以点击 C++ CGI Lib Documentation,查看相关的库文档。

    GET 和 POST 方法

    您可能有遇到过这样的情况,当您需要从浏览器传递一些信息到 Web 服务器,最后再传到 CGI 程序。通常浏览器会使用两种方法把这个信息传到 Web 服务器,分别是 GET 和 POST 方法。

    使用 GET 方法传递信息

    GET 方法发送已编码的用户信息追加到页面请求中。页面和已编码信息通过 ? 字符分隔开,如下所示:

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

    GET 方法是默认的从浏览器向 Web 服务器传信息的方法,它会在浏览器的地址栏中生成一串很长的字符串。当您向服务器传密码或其他一些敏感信息时,不要使用 GET 方法。GET 方法有大小限制,在一个请求字符串中最多可以传 1024 个字符。

    当使用 GET 方法时,是使用 QUERY_STRING http 头来传递信息,在 CGI 程序中可使用 QUERY_STRING 环境变量来访问。

    您可以通过在 URL 后跟上简单连接的键值对,也可以通过使用 HTML

    标签的 GET 方法来传信息。

    简单的 URL 实例:Get 方法

    下面是一个简单的 URL,使用 GET 方法传递两个值给 hello_get.py 程序。

    /cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

    下面的实例生成 cpp_get.cgi CGI 程序,用于处理 Web 浏览器给出的输入。通过使用 C++ CGI 库,可以很容易地访问传递的信息:

    实例

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace std;
    11. using namespace cgicc;
    12. int main ()
    13. {
    14. Cgicc formData;
    15. cout << "Content-type:text/html\r\n\r\n";
    16. cout << "\n";
    17. cout << "\n";
    18. cout << "使用 GET 和 POST 方法\n";
    19. cout << "\n";
    20. cout << "\n";
    21. form_iterator fi = formData.getElement("first_name");
    22. if( !fi->isEmpty() && fi != (*formData).end()) {
    23. cout << "名:" << **fi << endl;
    24. }else{
    25. cout << "No text entered for first name" << endl;
    26. }
    27. cout << "
      \n"
      ;
    28. fi = formData.getElement("last_name");
    29. if( !fi->isEmpty() &&fi != (*formData).end()) {
    30. cout << "姓:" << **fi << endl;
    31. }else{
    32. cout << "No text entered for last name" << endl;
    33. }
    34. cout << "
      \n"
      ;
    35. cout << "\n";
    36. cout << "\n";
    37. return 0;
    38. }

    现在,编译上面的程序,如下所示:

    $g++ -o cpp_get.cgi cpp_get.cpp -lcgicc

    生成 cpp_get.cgi,并把它放在 CGI 目录中,并尝试使用下面的链接进行访问:

    /cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

    这会产生以下结果:

    名:ZARA 
    姓:ALI 

    简单的表单实例:GET 方法

    下面是一个简单的实例,使用 HTML 表单和提交按钮传递两个值。我们将使用相同的 CGI 脚本 cpp_get.cgi 来处理输入。

    1. "/cgi-bin/cpp_get.cgi" method="get">
    2. 名:"text" name="first_name">
    3. 姓:"text" name="last_name" />
    4. "submit" value="提交" />

    下面是上述表单的实际输出,请输入名和姓,然后点击提交按钮查看结果。

    使用 POST 方法传递信息

    一个更可靠的向 CGI 程序传递信息的方法是 POST 方法。这种方法打包信息的方式与 GET 方法相同,不同的是,它不是把信息以文本字符串形式放在 URL 中的 ? 之后进行传递,而是把它以单独的消息形式进行传递。该消息是以标准输入的形式传给 CGI 脚本的。

    我们同样使用 cpp_get.cgi 程序来处理 POST 方法。让我们以同样的例子,通过使用 HTML 表单和提交按钮来传递两个值,只不过这次我们使用的不是 GET 方法,而是 POST 方法,如下所示:

    1. "/cgi-bin/cpp_get.cgi" method="post">
    2. 名:"text" name="first_name">
    3. 姓:"text" name="last_name" />
    4. "submit" value="提交" />

    向 CGI 程序传递复选框数据

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

    下面的 HTML 代码实例是一个带有两个复选框的表单:

    1. "/cgi-bin/cpp_checkbox.cgi"
    2. method="POST"
    3. target="_blank">
    4. "checkbox" name="maths" value="on" /> 数学
    5. "checkbox" name="physics" value="on" /> 物理
    6. "submit" value="选择学科" />

    下面的 C++ 程序会生成 cpp_checkbox.cgi 脚本,用于处理 Web 浏览器通过复选框给出的输入。

    实例

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace std;
    11. using namespace cgicc;
    12. int main ()
    13. {
    14. Cgicc formData;
    15. bool maths_flag, physics_flag;
    16. cout << "Content-type:text/html\r\n\r\n";
    17. cout << "\n";
    18. cout << "\n";
    19. cout << "向 CGI 程序传递复选框数据\n";
    20. cout << "\n";
    21. cout << "\n";
    22. maths_flag = formData.queryCheckbox("maths");
    23. if( maths_flag ) {
    24. cout << "Maths Flag: ON " << endl;
    25. }else{
    26. cout << "Maths Flag: OFF " << endl;
    27. }
    28. cout << "
      \n"
      ;
    29. physics_flag = formData.queryCheckbox("physics");
    30. if( physics_flag ) {
    31. cout << "Physics Flag: ON " << endl;
    32. }else{
    33. cout << "Physics Flag: OFF " << endl;
    34. }
    35. cout << "
      \n"
      ;
    36. cout << "\n";
    37. cout << "\n";
    38. return 0;
    39. }

    向 CGI 程序传递单选按钮数据

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

    下面的 HTML 代码实例是一个带有两个单选按钮的表单:

    1. "/cgi-bin/cpp_radiobutton.cgi"
    2. method="post"
    3. target="_blank">
    4. "radio" name="subject" value="maths"
    5. checked="checked"/> 数学
    6. "radio" name="subject" value="physics" /> 物理
    7. "submit" value="选择学科" />

    下面的 C++ 程序会生成 cpp_radiobutton.cgi 脚本,用于处理 Web 浏览器通过单选按钮给出的输入。

    实例

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace std;
    11. using namespace cgicc;
    12. int main ()
    13. {
    14. Cgicc formData;
    15. cout << "Content-type:text/html\r\n\r\n";
    16. cout << "\n";
    17. cout << "\n";
    18. cout << "向 CGI 程序传递单选按钮数据\n";
    19. cout << "\n";
    20. cout << "\n";
    21. form_iterator fi = formData.getElement("subject");
    22. if( !fi->isEmpty() && fi != (*formData).end()) {
    23. cout << "Radio box selected: " << **fi << endl;
    24. }
    25. cout << "
      \n"
      ;
    26. cout << "\n";
    27. cout << "\n";
    28. return 0;
    29. }

    向 CGI 程序传递文本区域数据

    当需要向 CGI 程序传递多行文本时,我们使用 TEXTAREA 元素。

    下面的 HTML 代码实例是一个带有 TEXTAREA 框的表单:

    1. "/cgi-bin/cpp_textarea.cgi"
    2. method="post"
    3. target="_blank">
    4. "submit" value="提交" />

    下面的 C++ 程序会生成 cpp_textarea.cgi 脚本,用于处理 Web 浏览器通过文本区域给出的输入。

    实例

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace std;
    11. using namespace cgicc;
    12. int main ()
    13. {
    14. Cgicc formData;
    15. cout << "Content-type:text/html\r\n\r\n";
    16. cout << "\n";
    17. cout << "\n";
    18. cout << "向 CGI 程序传递文本区域数据\n";
    19. cout << "\n";
    20. cout << "\n";
    21. form_iterator fi = formData.getElement("textcontent");
    22. if( !fi->isEmpty() && fi != (*formData).end()) {
    23. cout << "Text Content: " << **fi << endl;
    24. }else{
    25. cout << "No text entered" << endl;
    26. }
    27. cout << "
      \n"
      ;
    28. cout << "\n";
    29. cout << "\n";
    30. return 0;
    31. }

    向 CGI 程序传递下拉框数据

    当有多个选项可用,但只能选择一个或两个选项时,我们使用下拉框。

    下面的 HTML 代码实例是一个带有下拉框的表单:

    1. "/cgi-bin/cpp_dropdown.cgi"
    2. method="post" target="_blank">
    3. "submit" value="提交"/>

    下面的 C++ 程序会生成 cpp_dropdown.cgi 脚本,用于处理 Web 浏览器通过下拉框给出的输入。

    实例

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace std;
    11. using namespace cgicc;
    12. int main ()
    13. {
    14. Cgicc formData;
    15. cout << "Content-type:text/html\r\n\r\n";
    16. cout << "\n";
    17. cout << "\n";
    18. cout << "向 CGI 程序传递下拉框数据\n";
    19. cout << "\n";
    20. cout << "\n";
    21. form_iterator fi = formData.getElement("dropdown");
    22. if( !fi->isEmpty() && fi != (*formData).end()) {
    23. cout << "Value Selected: " << **fi << endl;
    24. }
    25. cout << "
      \n"
      ;
    26. cout << "\n";
    27. cout << "\n";
    28. return 0;
    29. }
  • 相关阅读:
    Java+SpringBoot+Vue自习室预约系统全栈开发
    New SQL
    Algorithm:网络广告营销领域之归因分析/归因模型的简介、算法、案例应用之详细攻略
    GraphQL 进阶——DataLoader
    设计模式之状态模式
    21年-05-自研-自我准备
    OpenMP入门
    【原理篇】一、声明Bean的八种方式
    旅游管理系统-JAVA【数据库设计、源码、开题报告】
    使用Caffeine实现帖子的缓存来优化网站的运行速度
  • 原文地址:https://blog.csdn.net/DUXS11/article/details/126398807