構建web應用會遇到的問題
請求方法的判斷
URL路徑的解析
URL中查詢字符串的解析
Cookie的解析
表單數據得解析
任意格式文件的上傳處理
會話的需求
請求方法
web請求方法存在于報文的第一行的第一個單詞,通常大寫
curl -v url
HTTP_Parser在解析請求報文的時候,將報文抽取出來,設置為req.method。存在的相應有POST、DELETE、PUT、GET。
PUT代表新建一個資源,POST表示要更新一個資源,GET表示查看一個資源,而DELETE表示刪除一個資源
路徑解析
客戶端代理(瀏覽器)會將這個地址解析成報文,將路徑和查詢的部分放在報文的第一行。最常見的根據路徑進行業務的應用是靜態文件服務器,它會根據路徑去查找磁盤中的文件,然后將其相應給客戶端
http://user:pass@host.com:8080/p/a/t/h?query=string
查詢字符串
查詢字符串位于路徑之后,在地址欄中路徑后的?foo=bar&baz=val字符串就是查詢字符串
這個字符串會跟隨在路徑之后,形成請求報文首行第二部分,為業務邏輯所用
Node提供了queryString 模塊用于處理這部分數據
var url = require('url');
var querystring = require('querystring');
var query = querystring.parse(url.parse(req.url).query);
它會將查詢字符串解析成一個JSON對象
{
foo:'bar',
baz:'val'
}
Cookie & Session
HTTP是一個無狀態協議,業務邏輯需要一定得狀態來區分用戶身份。
Cookie的處理分為以下幾步:
服務器像客戶端發送Cookie
瀏覽器將cookie保存
之后每次瀏覽器都會講Cookie發向服務器
cookie值得格式為 key = value;key=value形式
服務器告知客戶端設置cookie的值,在Set-Cookie字段中
Set-Cookie字段的格式為
Set-Cookie:name=value;Path=/; Expires=Sun, 23-Apr-23 09:01:35 GMT; Domain=.domain.com;
其中name=value是必須包含的部分,其余部分皆是可選參數。參數的意義:
path:表示這個Cookie影響的路徑,當前訪問的路徑不滿足改匹配時,瀏覽器不發送這個Cookie
Expires和Max-Age 告知瀏覽器這個Cookie何時過期,如果不設置該選項,在關閉瀏覽器時會丟失掉這個Cookie
HttpOnly 告知瀏覽器不允許通過腳本document.cookie來更改Cookie值。
Secure 當secure設置為true,在HTTP請求中這個Cookie是無效的,HTTPS中才有效
Cookie的性能影響:
由于Cookie的實現機制,一旦服務器向客戶端發送了設置Cookie的意圖,除非Cookie過期,否則客戶端每次請求都會發送這個寫Cookie到服務器端,一旦設置Cookie過多,會導致報文較大。
針對該問題做一下幾點優化
減小Cookie的大小 ?: 限定Cookie域
為靜態組件使用不同的域名: ?換域名減少無效Cookie的傳輸,引入的問題域名轉換為IP需要DNS查詢,多一個域名多一次DNS查詢
減少DNS查詢: ?沖突規則,現在瀏覽器都會進行DNS緩存
Cookie除了服務器可以設置,客戶端也可以通過Document.cookie進行修改,修改后,在后續的網絡請求中就會攜帶上修改后的值
Session
Cookie的缺點,1.會存在體積過大 2 前后端都可進行修改,數據容易被篡改和偽造
Session 的數據只保留在服務器端,客戶端無法進行修改,數據也無須在協議中每次都被傳遞
利用Session如何將每個客戶端與服務器對應起來,常見有以下方式
1.基于Cookie來實現用戶和數據得映射
cookie中只存放口令,服務器接受到Cookie口令去找對應的Session。
這是目前大多數web應用的方案,如果客戶端禁止使用Cookie,瞎
2.通過查詢字符串來實現瀏覽器和服務器端數據的對應。風險比較大
Session 與內存
session引入的問題
1.Session 存放在內存中,用戶量增多,內存量的數據會加大,會引起垃圾回收的頻繁掃描,影響性能。極端會耗盡內存
2.利用多核CPU開啟多個進程啟動服務,用戶的連接請求會被隨意分配到各個進程中,Node的進程與進程之間不能直接共享內存,用戶的Session可能會引起混亂,這種問題通過Session集中化,將Session存在緩存中,目前redis,memcached等
數據上傳
Node的http模塊只對HTTP報文的頭部進行解析,然后觸發request事件,如果請求中還帶有內容部分,內容部分需要用戶自行接受和解析。可以通過Transfer-Encoding或Content-Length即可判斷請求中是否帶有內容
表單數據
最為常見的數據提交是網頁表單提交數據到服務器端
默認的表單提交,請求頭中的Content-Type字段值為applicant/x-www-form-urlencoded
由于它的內容跟查詢字符串相同
req.body = query string.parase(req.rawBody);
后續的業務直接訪問req.body就可以
其他格式
除了表單數據外,常見的提交還有JSON/XML文件等,判斷和解析的原理都是依據content-type中的值決定。
其中JSON類型的值為application/json ,XML 的值為 application/xml
附件上傳
附件的上傳表單中含有file類型控件,以及需要制定表單屬性encpty為multipart/form-data
瀏覽器在遇到multipart/form-data表單提交時,構造的請求報文與普通表單完全不同,其中報頭
content-type:multipart/form-data; boundary=AaBo3x
content-length:18321;
它代表本次提交內容是由多部分構成,其中boundary代表每部分的分界符,隨機產生。
流式解析報文,這里提到的模塊為formidable。將接受到的文件寫入到系統臨時文件夾中,并返回對應的路徑。
數據上傳內存問題
內存限制:數據上傳請求并發量大如果文件存放在內存中,服務器內存很快耗盡。
解決方案:1.限制上傳內容的大小。2.采用流式解析,將數據流導向磁盤匯總,Node只保留文件路徑等小數據
路由解析
文件路徑型
1.靜態文件
請求路徑對應服務器文件,比較簡單
2.動態文件
web服務器根據URL路徑找到對應的文件,WEB服務器根據文件名后綴去尋找腳本的解析器,并傳入HTTP請求的上下文。
MVC
用戶的請求的URL路徑可以跟具體的腳本所以得路徑沒有任何關系。
use('/user/setting', exports.setting);
MVC模型叫業務邏輯按職責分離
工作模式如下:
路由解析,根據URL尋找到對應的控制器和行為。
行為調用相關的模型,進行數據操作
數據操作結束后,調用視圖和相關數據進行頁面渲染,輸出到客戶端。
URL 做路由映射,有兩種方式1.手工關聯映射。2.自然關聯映射。
優缺點:手動映射,如果項目較大,路由映射的數量也會很多,從路徑到具體的控制器,需要查看代碼才能知道。 自然關聯映射,如果URL變動,文件也需要變動,手工映射只需要更改路由映射即可
RESTful
representational state transfer 表現層轉態轉化
設計哲學主要將服務端提供的內容實體看做一個資源,并表現在URL上
例如:
/uses/jacksontian
這個地址代表一個資源,對這個資源的操作,主要體現在HTTP請求方法上,不體現在URL上。
過去對用戶的增刪改設計的URL為
POST ?/user/add?username=jack
GET ? /user/remove?username=jack
POST ?/user/update?username=jack
GET ? ?/user/get?username=jack
在RESTful設計中如下:
POST? /user/jack
DELETE ? /user/jack
PUT ?/user/jack
GET? ? /user/jack
將DEL PUT 請求方法引入到設計中,參與資源的操作和更改資源狀態
RESTful是對MVC更好的改進,相比較,只是將HTTP請求的方法加入了路由的過程,以及在url路徑上體現的更資源化
中間件 ? 自看
NODE 學習參考
1.Node.js 開發指南
2.深入淺出 node.js
3 Node.js實戰
https://github.com/yantao608/myblog