C++后台实践:古老的CGI与Web开发
本文写给C/C++程序猿,也适合其他对历史感兴趣的程序猿
=============================================
请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。
谈到web开发,大家首先想到的PHP、JavaEE/JSP、.NET/ASP、Ruby on rails、Python的Django等等。可谓百花齐放,你一般不会想到C++和Web开发有什么关系,但其实动态网页的开发(web开发)可是在这些动态网页语言诞生之前就存在了的。所以C/C++也是可以做web开发的,它利用的技术是——CGI。
在天地初开,混沌未分之时,动态网页语言尚未出世,要实现动态网站依赖的就是CGI。谷歌/百度一下CGI,可能会出现很多名词:CGI脚本、CGI程序、CGI标准等等。其实这些都是站在不同角度来说的,CGI即Common Gateway Interface的缩写,直译为“通用网关接口”。第一次听这个名字,我也不知道是个什么鬼东西。归根结底CGI就是一个接口协议。协议就是大家公认的一套标准(叫CGI标准也可以),比如网络协议。大家都遵守一套标准,就减少了沟通的难度。进行CGI开发,就是编写一个CGI可执行程序。其实各种语言都可以编写CGI,不但Java、Python、PHP、C#……可以,而且Shell也可以。当然C和C++也可以。由于早期CGI很多是由Perl(脚本语言)开发的,所以CGI程序也称CGI脚本,其实这个称呼不一定准确。因为C++编译出的可执行文件同样可以是CGI。
在PHP和Java大行其道的今天,很多人看来用C++编写CGI是几乎淘汰的技术了(其实这到不然,只是比较小众罢了)。所以如果你对C/C++感兴趣或者对历史感兴趣都可以阅读本文。
一次网页请求与响应
在进行网页浏览时,通常就是通过一个URL请求一个网页,然后服务器返回这个网页文件给浏览器。浏览器在本地解析该文件渲染成我们看到的网页。然而通常我们看到的网页不是静态网页,也就是说在服务端是没有这个网页文件,它是在网页请求的时候动态生成的,比如PHP/JSP网页。依据你请求的参数不同,所返回的内容不同。
同理,如果是请求一个CGI程序的时候(比如在浏览器直接输入CGI程序的URL,或者提交表单的时候发送给CGI程序),CGI程序负责解析从前端传递过来的参数,理解它的意图然后返回数据,比如返回HTML、XML或JSON等。
WARNNING:Apache默认没有打开CGI的支持,需要进行CGI的配置。具体方法可以自行百度。
预备前端知识
假设你是一个C++程序员,你可能对前端不熟(OK,我也不熟),在接下来的讲述之前,你要先掌握一些预备的前端知识(尽量少讲前端),你不需要知道如何渲染出一个美轮美奂的网页,但你需要知道前、后端如何交互。前端页面如何发送数据,一个普通的HTML页面通常的做法,你只需知道如下几种:
这里知讲第一种(最简单的):
[html]
表单提交用户名:密码:
form标签的action属性的值表示的就是表单要提交到url,即表单提交以后要跳转的页面(Ajax可以达到无跳转拉取数据,刷新页面),这里action属性值的是cgi程序的url地址。(WARNNING:/ 对应的是网站根目录,而不是Linux文件系统根目录哦)。method属性表示数据请求方式,有两种:get和post。不赘述。
我输入用户名jellywang,密码123456之后,点击OK按钮,即向当前域名/cgi-bin/hello.cgi的程序序提交了表单,并且携带参数username=jellywang。然后页面会跳转到这个cgi(就像普通网页跳转,浏览器地址栏更新一样)。
如果是get请求。那么浏览器地址栏的URL看起来像这样:localhost:/cgi-bin/hello.cgi?username=jelly&password=123456。很显然这是一种不够安全的方式,所以我们还可以使用post请求。这样地址栏就看不到这种提交的参数了。(其实post也不够安全,不鼓励直接提交明文密码的方式,本文仅作示例,安全登录不上本文重点)
环境变量与CGI处理
当前端页面通过get或post方法向cgi程序提交了数据以后,那么接下来cgi程序该如何解析呢?答案是环境变量。无论是Linux系统或Windows系统都有环境变量的概念。Linux用户在配置很多环境的时候,都不得不在系统配置文件中和环境变量打交道。CGI程序即是通过从环境变量中取值来获得参数的。这里介绍几个环境变量(更多的请自行百度):
REQUEST_METHOD
前端页面数据请求方式:get/post
QUERY_STRING
采用GET时所传输的信息
CONTENT_LENGTH
STDIO中的有效信息长度
SCRIPT_NAME
所调用的CGI程序的名字
SERVER_NAME
服务器的IP或名字
SERVER_PORT
主机的端口号
这些环境变量是从何而来,是谁定义的?是Linux吗?POSIX吗?当然不是。这里就要再次声明一下CGI是一个接口协议,这些环境变量就是属于该协议的内容,所以不论你的server所在的操作系统是Linux还是Windows,也不论你的server是Apache还是Nginx,这些变量的名称和含义都是一样的。实际就是Apache/Nginx在将这些内容填充到环境变量中,而具体填充规范则来自于CGI接口协议。
在C语言标准中有获取环境变量值得库函数——getenv。(头文件stdlib.h)
[cpp]
//比如chr*str=NULL;str=getenv("QUERY_STRING");
对于get请求,可以从环境变量QUERY_STRING中取出字符串 username=jelly&password=123456。然后程序自己做字符串的解析操作,解析出参数的key和value。而对于post请求,则是直接通过标注输入(STDIN)来获取这个参数字符串,比如使用scanf或cin都可以。
在解析了请求、进行了相应的逻辑处理之后(比如检查用户名密码是否一致),CGI程序要向前端页面返回内容,这是通过标准输出(STDOUT)完成的,比如printf或cout,你可以返回xml,json,plain text或一个html网页等等。这一步完成的是就是HTTP的响应过程。所以在返回直接的数据之前,要先输出HTTP协议的首部。比如,假设你想返回一个html网页,那么你首先要输出:
[cpp]
cout
暂无评论内容