Node.js 獲取GET、POST提交的資料
表單提交過來的資料有兩種方法,一種是GET方式提交,這種提交方法會把表單需要傳輸的資料寫在url上,一起帶過去,另一種是POST方式提交,POST方式提交會把表單資料攜帶在request請求正文中傳遞過去。
針對這兩種不同的提交方法,node裡也有兩種不同的處理方法。先看看如果用GET方式提交,我們該怎麼去處理
獲取GET方式提交的資料
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title> </title>
</head>
<body>
<form action="http://localhost:9998" method="get">
<input type="text" name="user" value="" />
<input type="password" name="passw" value="" />
<input type="submit" value=""/>
</form >
</body>
</html>
index.html只是一個簡單的表單網頁,兩個輸入框用作使用者的賬號和密碼輸入,還有一個submit用來提交。
下面是node實現
GETServer.js
var http = require("http");
var url = require("url");
function onRequest(req,resp){
console.log(url.parse(req.url,true).query);
//返回響應
resp.writeHead(200,{"ContentType" :"text/html;charset=utf-8"});
resp.end();
}
//建立server
http.createServer(onRequest).listen(9998);
這樣的話就獲取到了表單使用GET方式提交過來的資料
其中req.url 是指req提交過來的url的路由
但是我們會發現一個問題,我們看一下console的列印情況。
{ user: 'asda', passw: 'asddasd' }
{}
我們會發現列印了兩行,第二行被打印出了一個空的JSON物件。這是怎麼回事呢,聽老衲緩緩道來。
在第一次request請求的時候,客戶端會發送一個隱式的請求給伺服器,這個請求就是為了獲取到網頁的圖示(就是每個網頁開啟後Title旁邊的那個小圖示),所以,當我們提交表單資料的時候,實際是觸發了兩次請求,第一次請求favicon.ico ,第二次提交資料,所以我們打印出來的結果就是兩個物件。
so?那麼我們應該怎樣去處理它呢?我們需要在服務端過濾掉請求favicon.ico的請求。
只需加上一段這樣的if就行
if(req.url != "/favicon.ico"){
console.log(url.parse(req.url,true).query);
}
這樣的話我們再看一下console的列印結果是不是正常了
{ user: 'asda', passw: 'asddasd' }
獲取POST方式提交的資料
開頭我也說過了,用POST方式提交的資料會附帶在請求正文裡面,所以我們需要獲取到附帶在request正文裡的資訊,那具體是怎麼做呢?
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<form action="http://localhost:9998" method="post">
<input type="text" name="user" value="" />
<input type="password" name="passw" value="" />
<input type="submit" value=""/>
</form>
</body>
</html>
這裡只做了簡單的修改,把method 從get改為post
POSTServer.js
/**
* New node file
*/
var http = require("http");
var queryString = require("querystring");
function onRequest(req,resp){
//過濾掉favicon請求
if(req.url != "/favicon.ico"){
//post請求 獲取表單資料
var obj = null;
var currentData = "";
req.on("data",function(data){
currentData += data;
obj = queryString.parse(currentData);
});
console.log(obj);
resp.writeHead(200,{"ContentType":"text/html;charset=utf-8"});
resp.end();
}
}
//建立server
http.createServer(onRequest).listen(9998);
上面的querystring.parse就能直接把獲取到的資料轉換成JSON物件。
接下來我們來看看控制檯是怎麼列印的
null
what!?
為什麼是null!?
這就說明如果要學習Node就得改掉我們寫java ,寫C/C++ 那些非非同步的語言的程式設計習慣,因為這裡的原因之所以是Null是因為Node本身機制的原因
Node的快就在於它處處存在非同步,存在回撥,基於觀察者模式於一身的美男子。
這裡我不得不說一下Node的非同步執行機制。
下面我畫一張醜圖僅供大家參考。
看不清的朋友右鍵檢視原圖把。
畫的有點醜大家湊合著看,我來簡單的說明一下這幅圖。
整個Node程式在執行的過程中,遇到了sync Event 也就是同步事件,然後直譯器會把它交給一個叫做事件棧(Event Stack)的資料結構,這個棧會不斷的去push同步程式碼,然後執行完畢後pop出來。當程式遇到非同步事件(async Event)的時候,會把它交給別的地方來處理,處理完畢後將結果返回至事件佇列(Event Queue),當Event Stack空閒的時候,就會讓一個Loop來挨個挨個將事件佇列中的事件取出來,放入事件棧裡執行回撥。
這時我們就可以解釋為什麼是null了,因為request 綁定了一個名為data的非同步事件,但是我們console.log(obj);是sync的,所以直譯器會先打印出obj的值,再去事件佇列中取出來放到事件棧中去執行回撥,雖然我們程式碼順序是先賦值,再列印,而結果卻出乎我們意料,是先列印再賦值,對於這種情況的解決辦法,我們初步可以呼叫setTimeout的方法來解決它。setTimeout() 是一個延遲執行的函式,用它可以將我們的console.log(obj);放入佇列尾,這樣的話,我們就能夠實現先賦值再列印了,當然這樣會降低程式的效率。
我們來修改一下程式的程式碼
POSTServer.js
/**
* New node file
*/
var http = require("http");
var queryString = require("querystring");
function onRequest(req,resp){
//過濾掉favicon請求
if(req.url != "/favicon.ico"){
//post請求 獲取表單資料
var obj = null;
var currentData = "";
req.on("data",function(data){
currentData += data;
obj = queryString.parse(currentData);
});
setTimeout(function(){
console.log(obj);
},1000);
resp.writeHead(200,{"ContentType":"text/html;charset=utf-8"});
resp.end();
}
}
//建立server
http.createServer(onRequest).listen(9998);
這樣的話我們就能看到console打印出來的正常的結果。
{ user: 'asda', passw: 'asddasd' }
完美處理POST、GET請求
接下來我們結合兩種方法來實現不管POST,GET提交的方式我們都能處理。
GETPOSTServer.js
/**
* New node file
*/
var http = require("http");
var url = require("url");
var queryString = require("querystring");
function onRequest(req,resp){
//過濾掉favicon請求
if(req.url != "/favicon.ico"){
//需要的json物件
var obj = null;
//區分get post 請求
if(req.method == "GET"){
obj = url.parse(req.url,true).query;
}
else{
//post請求 獲取表單資料
var currentData = "";
req.on("data",function(data){
currentData += data;
obj = queryString.parse(currentData);
});
}
//新增進事件佇列
setTimeout(function(){
console.log(obj);
},1000);
write(resp);
}
}
function write(resp){
resp.writeHead(200,{"ContentType":"text/html;charset=utf-8"});
resp.end();
}
//建立server
http.createServer(onRequest).listen(9998);
如果大家發現本篇博文有任何錯誤,都可以在回覆區反饋給我。我會及時改正,共勉!