您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關如何理解FastCGI協議,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
CGI全稱是“公共網關接口”(Common Gateway Interface),HTTP服務器與你的或其它機器上的程序進行“交談”的一種工具,其程序須運行在網絡服務器上。
cgi會產生什么問題呢?
當每一個請求進入的時候,cgi都會fork一個新的進程,然后以php為例,每個請求都要耗費相當大的內存,這樣一來,并發起來,完全就會GG。
為了解決這個問題,于是產生了fastCgi。
FastCGI像是一個常駐(long-live)型的CGI,它可以一直執行著,只要激活后,不會每次都要花費時間去fork一次(這是CGI最為人詬病的fork-and-execute 模式)。
它還支持分布式的運算,即 FastCGI 程序可以在網站服務器以外的主機上執行并且接受來自其它網站服務器來的請求。
http request:
Request URL: http://demo.inke.cn/server.php Request Method: GET Status Code: 200 OK Remote Address: 127.0.0.1:80 Referrer Policy: no-referrer-when-downgrade Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cache-Control: max-age=0 Connection: keep-alive Cookie: aid=fa29caf3-5b18-401c-8abd-677eb1a1c45f; s-59804d897bc03a0036dc141c=2a126bda133d4feba4169fa70308f2c7 Host: demo.inke.cn Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36
server.php
<?php var_dump($_SERVER); 返回結果: array(33) { ["USER"]=> string(6) "limars" ["HOME"]=> string(13) "/Users/limars" ["HTTP_COOKIE"]=> string(101) "aid=d11e3484-fd7d-4c6e-a2a5-bfabe2271da2; s-59804d897bc03a0036dc141c=fcb6a8cf23644f50b66e405d173eced7" ["HTTP_ACCEPT_LANGUAGE"]=> string(14) "zh-CN,zh;q=0.9" ["HTTP_ACCEPT_ENCODING"]=> string(13) "gzip, deflate" ["HTTP_ACCEPT"]=> string(118) "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3" ["HTTP_USER_AGENT"]=> string(121) "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36" ["HTTP_UPGRADE_INSECURE_REQUESTS"]=> string(1) "1" ["HTTP_CONNECTION"]=> string(10) "keep-alive" ["HTTP_HOST"]=> string(12) "demo.inke.cn" ["REDIRECT_STATUS"]=> string(3) "200" ["SERVER_NAME"]=> string(12) "demo.inke.cn" ["SERVER_PORT"]=> string(2) "80" ["SERVER_ADDR"]=> string(9) "127.0.0.1" ["REMOTE_PORT"]=> string(5) "51429" ["REMOTE_ADDR"]=> string(9) "127.0.0.1" ["SERVER_SOFTWARE"]=> string(12) "nginx/1.12.2" ["GATEWAY_INTERFACE"]=> string(7) "CGI/1.1" ["REQUEST_SCHEME"]=> string(4) "http" ["SERVER_PROTOCOL"]=> string(8) "HTTP/1.1" ["DOCUMENT_ROOT"]=> string(31) "/Users/limars/Desktop/inke/demo" ["DOCUMENT_URI"]=> string(11) "/server.php" ["REQUEST_URI"]=> string(11) "/server.php" ["SCRIPT_NAME"]=> string(11) "/server.php" ["CONTENT_LENGTH"]=> string(0) "" ["CONTENT_TYPE"]=> string(0) "" ["REQUEST_METHOD"]=> string(3) "GET" ["QUERY_STRING"]=> string(0) "" ["SCRIPT_FILENAME"]=> string(42) "/Users/limars/Desktop/inke/demo/server.php" ["FCGI_ROLE"]=> string(9) "RESPONDER" ["PHP_SELF"]=> string(11) "/server.php" ["REQUEST_TIME_FLOAT"]=> float(1565082651.4024) ["REQUEST_TIME"]=> int(1565082651) }
它是個怎樣的轉換過程呢?仔細觀察,我們會發現有很多東西是http協議里沒有的,那這些東西是怎么生成的呢?
觀察nginx配置:
listen 80; server_name demo.inke.cn; root /Users/limars/Desktop/inke/demo; location ~ \.php$ { try_files $uri =404; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }
我們會發現一個叫 fastcgi_param的可配置參數,而nginx一般提供了默認值。 打開nginx目錄下的fastcgi_params文件可以看到:
fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name;
這時候,我們對比下$_SERVER中http_XXX_XXX的,這不是都是http自帶的頭部嘛?
綜合下來,這就是一個http請求完整轉發到php的過程,一次完整的cgi請求,而fastcgi呢,就是對cgi協議的常駐封裝,主要解決的問題是:
優化性能(cgi不停fork新進程,每個進程都干很多同樣的事【加載配置文件、加載擴展】) 進程池維護,異步模型,請求是分發到空閑子進程,方便創建/銷毀進程。
const ( typeBeginRequest uint8 = 1 typeAbortRequest uint8 = 2 typeEndRequest uint8 = 3 typeParams uint8 = 4 typeStdin uint8 = 5 typeStdout uint8 = 6 typeStderr uint8 = 7 typeData uint8 = 8 typeGetValues uint8 = 9 typeGetValuesResult uint8 = 10 typeUnknownType uint8 = 11 )
見名知意:
1~3是信號類型
4~10是不同的數據類型
11、default 是錯誤類型
通常協議傳輸,為了考慮數據大小的原因,都會將數據進行分片處理,fcgi也同樣。
fcgi協議的每個包都由包頭和包體組成
//It's fcgi header type header struct { Version uint8 Type uint8 Id uint16 ContentLength uint16 PaddingLength uint8 Reserved uint8 }
包的正文,就是由分割的二進制內容組成,一個包最多傳輸2^16次方減一,也就是65535個字節。
一次完整的請求過程
請求:解析http請求獲取配置->發送cgi請求->typeBeginRequest -> write Params -> write Stdin(if exists) -> write Data (if exists)
//寫頭部 if request.KeepConn { //if it's keep-alive //set flags 1 err = cgi.writeBeginRequest(reqId, roleResponder, 1) } else { err = cgi.writeBeginRequest(reqId, roleResponder, 0) } if err != nil { return } //寫http header err = cgi.writePairs(typeParams, reqId, request.Params) if err != nil { return } //讀取http body并寫到cgi p := make([]byte, 1024) n, _ := request.Stdin.Read(p) err = cgi.writeRecord(typeStdin, reqId, p[:n]) //寫其他信息 //寫最后一個換行 err = cgi.writeRecord(typeStdin, reqId, nil)
接收:check response type-> 錯誤處理(stderr、unknownType、default)->正確類型->接受數據復用socket返回給請求方。 rec := &record{} //建立一個記錄緩沖
var err1 error // recive untill EOF or FCGI_END_REQUEST for { err1 = rec.read(cgi.rwc) //從cgi建立的鏈接讀取數據 if err1 != nil { //判斷是否有錯誤,判斷錯誤是否為終止符 if err1 != io.EOF { // keepalive on的時候 不會有終止符 這個要注意,讀完長度為content-length即當前請求返回 err = err1 } break } switch { //根據返回的類型,將內容寫到響應的字節數組中 case rec.h.Type == typeStdout: retout = append(retout, rec.content()...) case rec.h.Type == typeStderr: reterr = append(reterr, rec.content()...) case rec.h.Type == typeEndRequest: fallthrough default: break } }
看完上述內容,你們對如何理解FastCGI協議有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。