乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      古老的CGI與Web開發(fā)

       nxhujiee 2018-07-17

      C++后臺實(shí)踐:古老的CGI與Web開發(fā)

      本文寫給C/C++程序猿,也適合其他對歷史感興趣的程序猿

      =============================================

              談到web開發(fā),大家首先想到的PHP、JavaEE/JSP、.NET/ASP、Ruby on rails、Python的Django等等。可謂百花齊放,你一般不會想到C++和Web開發(fā)有什么關(guān)系,但其實(shí)動態(tài)網(wǎng)頁的開發(fā)(web開發(fā))可是在這些動態(tài)網(wǎng)頁語言誕生之前就存在了的。所以C/C++也是可以做web開發(fā)的,它利用的技術(shù)是——CGI。

              在天地初開,混沌未分之時,動態(tài)網(wǎng)頁語言尚未出世,要實(shí)現(xiàn)動態(tài)網(wǎng)站依賴的就是CGI。谷歌/百度一下CGI,可能會出現(xiàn)很多名詞:CGI腳本、CGI程序、CGI標(biāo)準(zhǔn)等等。其實(shí)這些都是站在不同角度來說的,CGI即Common Gateway Interface的縮寫,直譯為“通用網(wǎng)關(guān)接口”。第一次聽這個名字,我也不知道是個什么鬼東西。歸根結(jié)底 CGI就是一個接口協(xié)議。協(xié)議就是大家公認(rèn)的一套標(biāo)準(zhǔn)(叫CGI標(biāo)準(zhǔn)也可以),比如網(wǎng)絡(luò)協(xié)議。大家都遵守一套標(biāo)準(zhǔn),就減少了溝通的難度。進(jìn)行CGI開發(fā),就是編寫一個CGI可執(zhí)行程序。其實(shí)各種語言都可以編寫CGI,不但Java、Python、PHP、C#……可以,而且Shell也可以。當(dāng)然C和C++也可以。由于早期CGI很多是由Perl(腳本語言)開發(fā)的,所以CGI程序也稱CGI腳本,其實(shí)這個稱呼不一定準(zhǔn)確。因?yàn)镃++編譯出的可執(zhí)行文件同樣可以是CGI。

              在PHP和Java大行其道的今天,很多人看來用C++編寫CGI是幾乎淘汰的技術(shù)了(其實(shí)這到不然,只是比較小眾罷了)。所以如果你對C/C++感興趣或者對歷史感興趣都可以閱讀本文。

      一次網(wǎng)頁請求與響應(yīng)

              在進(jìn)行網(wǎng)頁瀏覽時,通常就是通過一個URL請求一個網(wǎng)頁,然后服務(wù)器返回這個網(wǎng)頁文件給瀏覽器。瀏覽器在本地解析該文件渲染成我們看到的網(wǎng)頁。然而通常我們看到的網(wǎng)頁不是靜態(tài)網(wǎng)頁,也就是說在服務(wù)端是沒有這個網(wǎng)頁文件,它是在網(wǎng)頁請求的時候動態(tài)生成的,比如PHP/JSP網(wǎng)頁。依據(jù)你請求的參數(shù)不同,所返回的內(nèi)容不同。
              同理,如果是請求一個CGI程序的時候(比如在瀏覽器直接輸入CGI程序的URL,或者提交表單的時候發(fā)送給CGI程序),CGI程序負(fù)責(zé)解析從前端傳遞過來的參數(shù),理解它的意圖然后返回數(shù)據(jù),比如返回HTML、XML或JSON等。
      WARNNING:Apache默認(rèn)沒有打開CGI的支持,需要進(jìn)行CGI的配置。具體方法可以自行百度。

      預(yù)備前端知識

              假設(shè)你是一個C++程序員,你可能對前端不熟(OK,我也不熟),在接下來的講述之前,你要先掌握一些預(yù)備的前端知識(盡量少講前端),你不需要知道如何渲染出一個美輪美奐的網(wǎng)頁,但你需要知道前、后端如何交互。前端頁面如何發(fā)送數(shù)據(jù),一個普通的HTML頁面通常的做法,你只需知道如下幾種:
      • form表單提交(html原生)
      • js操縱下的表單提交
      • js通過Ajax請求數(shù)據(jù)
      這里知講第一種(最簡單的):
      [html] view plain copy
       在CODE上查看代碼片派生到我的代碼片
      1. <h1>表單提交</h1>  
      2. <form action="/cgi-bin/hello.cgi" method="get">  
      3. <table>  
      4.     <tr>  
      5.         <td>用戶名:</td>  
      6.         <td><input name="username"/></td>  
      7.     </tr>  
      8.         <tr>  
      9.         <td>密碼:</td>  
      10.         <td><input name="password"/></td>  
      11.     </tr>  
      12.     <tr>  
      13.         <td><input type="submit" value="OK"/></td>  
      14.     </tr>  
      15.     </table>  
      16. </form>  


      form標(biāo)簽的action屬性的值表示的就是表單要提交到url,即表單提交以后要跳轉(zhuǎn)的頁面(Ajax可以達(dá)到無跳轉(zhuǎn)拉取數(shù)據(jù),刷新頁面),這里action屬性值的是cgi程序的url地址。(WARNNING:/ 對應(yīng)的是網(wǎng)站根目錄,而不是Linux文件系統(tǒng)根目錄哦)。method屬性表示數(shù)據(jù)請求方式,有兩種:get和post。不贅述。

              我輸入用戶名jellywang,密碼123456之后,點(diǎn)擊OK按鈕,即向 當(dāng)前域名/cgi-bin/hello.cgi 的程序序提交了表單,并且攜帶參數(shù)username=jellywang。然后頁面會跳轉(zhuǎn)到這個cgi(就像普通網(wǎng)頁跳轉(zhuǎn),瀏覽器地址欄更新一樣)。
              如果是get請求。那么瀏覽器地址欄的URL看起來像這樣:localhost:/cgi-bin/hello.cgi?username=jelly&password=123456。很顯然這是一種不夠安全的方式,所以我們還可以使用post請求。這樣地址欄就看不到這種提交的參數(shù)了。(其實(shí)post也不夠安全,不鼓勵直接提交明文密碼的方式,本文僅作示例,安全登錄不上本文重點(diǎn))

      環(huán)境變量與CGI處理

              當(dāng)前端頁面通過get或post方法向cgi程序提交了數(shù)據(jù)以后,那么接下來cgi程序該如何解析呢?答案是環(huán)境變量。無論是Linux系統(tǒng)或Windows系統(tǒng)都有環(huán)境變量的概念。Linux用戶在配置很多環(huán)境的時候,都不得不在系統(tǒng)配置文件中和環(huán)境變量打交道。CGI程序即是通過從環(huán)境變量中取值來獲得參數(shù)的。這里介紹幾個環(huán)境變量(更多的請自行百度):

      REQUEST_METHOD

      前端頁面數(shù)據(jù)請求方式:get/post

      QUERY_STRING

      采用GET時所傳輸?shù)男畔?/p>

      CONTENT_LENGTH

      STDIO中的有效信息長度

      SCRIPT_NAME

      所調(diào)用的CGI程序的名字

      SERVER_NAME

      服務(wù)器的IP或名字

      SERVER_PORT

      主機(jī)的端口號


              這些環(huán)境變量是從何而來,是誰定義的?是Linux嗎?POSIX嗎?當(dāng)然不是。這里就要再次聲明一下CGI是一個接口協(xié)議,這些環(huán)境變量就是屬于該協(xié)議的內(nèi)容,所以不論你的server所在的操作系統(tǒng)是Linux還是Windows,也不論你的server是Apache還是Nginx,這些變量的名稱和含義都是一樣的。實(shí)際就是Apache/Nginx在將這些內(nèi)容填充到環(huán)境變量中,而具體填充規(guī)范則來自于CGI接口協(xié)議。
              在C語言標(biāo)準(zhǔn)中有獲取環(huán)境變量值得庫函數(shù)——getenv。(頭文件stdlib.h)
      [cpp] view plain copy
       在CODE上查看代碼片派生到我的代碼片
      1. //比如  
      2. chr* str = NULL;  
      3. str = getenv("QUERY_STRING");  
              對于get請求,可以從環(huán)境變量QUERY_STRING中取出字符串 username=jelly&password=123456。然后程序自己做字符串的解析操作,解析出參數(shù)的key和value。而對于post請求,則是直接通過標(biāo)注輸入(STDIN)來獲取這個參數(shù)字符串,比如使用scanf或cin都可以。
              在解析了請求、進(jìn)行了相應(yīng)的邏輯處理之后(比如檢查用戶名密碼是否一致),CGI程序要向前端頁面返回內(nèi)容,這是通過標(biāo)準(zhǔn)輸出(STDOUT)完成的,比如printf或cout,你可以返回xml,json,plain text或一個html網(wǎng)頁等等。這一步完成的是就是HTTP的響應(yīng)過程。所以在返回直接的數(shù)據(jù)之前,要先輸出HTTP協(xié)議的首部。比如,假設(shè)你想返回一個html網(wǎng)頁,那么你首先要輸出:
      [cpp] view plain copy
       在CODE上查看代碼片派生到我的代碼片
      1. cout<<"Content-Type:text/html\n\n"<<endl;  
      WARNNING:這里要注意,一定要輸出兩個換行符(\n)。因?yàn)镠TTP協(xié)議的首部和消息實(shí)體(如HTML代碼)之間用空行分割。
              后面直接cout出html代碼(比如輸出你剛才輸入的用戶名成功登陸)。前端頁面就會收到這些html代碼,然后瀏覽器就渲染成網(wǎng)頁啦。這就是一次CGI完成的動態(tài)網(wǎng)頁操作了。 

      Cgicc庫

              進(jìn)行C++的CGI編程,需要手動進(jìn)行字符串的解析處理,還有自行管理首部。比如資源轉(zhuǎn)移了,要返回302,并且在首部用Location給出新地址。很顯然,這些東西對于PHP、Python等語言都有內(nèi)置的解決方案。對于C++就需要第三方庫了。這里推薦一個GNU的開源庫——Cgicc??梢詽M足常用的各類需求,除了解析get/post請求外,還能重定向,還可以設(shè)置Cookie,還可以上傳文件等等等等。
              美中不足的就是Cgicc庫不支持SESSION。但是這個問題不大,我們可以很容易使用Cookie來實(shí)現(xiàn)SESSION功能。由于CGI本身是請求一次就創(chuàng)建一個進(jìn)程,返回之后進(jìn)程就結(jié)束(下文的FastCGI除外)。這時要在服務(wù)端維持一個SESSION的變量可選的解決方案是:用文件存儲或者在Redis、Memcached等內(nèi)存數(shù)據(jù)庫中存儲。而發(fā)給客戶端的SESSIONID就用Cgicc已經(jīng)支持的Cookie功能來完成,就可以了。

      CGI的痛點(diǎn)與FastCGI

              CGI是一種標(biāo)準(zhǔn),并不限定語言。所以Java、PHP、Python都可以通過這種方式來生成動態(tài)網(wǎng)頁。但是實(shí)際上這些動態(tài)語言卻很少這樣用。原來是CGI有一大硬傷。那就是每次CGI請求,那么Apache都有啟動一個進(jìn)程去執(zhí)行這個CGI程序,即頗具Unix特色的fork-and-execute。當(dāng)用戶請求量大的時候,這個fork-and-execute的操作會嚴(yán)重拖慢Server的進(jìn)程。而Java的Servlet技術(shù)則是一種常駐內(nèi)存的技術(shù),不會頻繁的發(fā)生進(jìn)程上下文的創(chuàng)建和銷毀操作。
              時勢造英雄,F(xiàn)astCGI技術(shù)應(yīng)運(yùn)而生。簡單來說,其本質(zhì)就是一個常駐內(nèi)存的進(jìn)程池技術(shù),由調(diào)度器負(fù)責(zé)將傳遞過來的CGI請求發(fā)送給處理CGI的handler進(jìn)程來處理。在一個請求處理完成之后,該處理進(jìn)程不銷毀,繼續(xù)等待下一個請求的到來。FCGI技術(shù)一出,CGI又一定程度上煥發(fā)了第二春。PHP-FPM本身是使PHP支持FCGI技術(shù)的一個Patch,現(xiàn)在已經(jīng)被納入PHP標(biāo)準(zhǔn)。當(dāng)然,支持C++的FCGI技術(shù)也出現(xiàn)了,Apache有FCGI的模塊可以安裝,比如mod_fcgid。

      現(xiàn)代CGI的編程范式

              前面我們知道,CGI可以直接返回一個html網(wǎng)頁。CGI程序本身也可以進(jìn)行各種計算、邏輯處理任務(wù)。隨著各類web前后端技術(shù)的發(fā)展,以及大數(shù)據(jù)、高并發(fā)的Server使用場景越來越多。現(xiàn)代的CGI的用法,在發(fā)生變化。
              現(xiàn)在,越來越多的任務(wù)從后端轉(zhuǎn)移到前端,前端頁面利用豐富的Js技術(shù)來進(jìn)行更多的處理。
      1. JS可以使用Ajax技術(shù)來向后臺CGI發(fā)起數(shù)據(jù)請求。Ajax完成的是不需要刷新整個頁面就可以加載后端數(shù)據(jù)(比如從數(shù)據(jù)庫中取出)。
      2. CGI一般不再用于直接返回html頁面,同時將復(fù)雜的計算、IO任務(wù)下沉到后端(后端可以進(jìn)一步進(jìn)行路由轉(zhuǎn)發(fā),實(shí)現(xiàn)負(fù)載均衡)。使CGI作為前后端之間的中間層。彼時CGI的職能是完成基本的數(shù)據(jù)交換:解析前端數(shù)據(jù)請求,再轉(zhuǎn)發(fā)給對應(yīng)后端;然后從后端取回數(shù)據(jù),給前端返回XML或JSON。
      3. 前端JS利用XML/JSON中的數(shù)據(jù)來進(jìn)行填充,繪制出豐富的頁面。
      上一篇CGI程序中POST和GET消息的處理

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多