2013-03-15 209 views
39

我試圖處理髮送到我的node.js服務器的post請求。 名稱爲server.js的JavaScript文件在瀏覽器上顯示一個表單。我想要在表單值被髮布到node.js後端後訪問表單值。如何在node.js中處理POST請求

表單包含用戶名,存儲庫和分支。提交表單時,我想將這些數據返回給用戶。

的server.js代碼:

var http = require('http'); 

http.createServer(function (request, response) { 
response.writeHead(200, {'Content-Type': 'text/html'}); 
response.end('<html><body>' 
    + '<h1>XYZ Repository Commit Monitor</h1>' 
    + '<form method="post" action="." enctype="application/x-www-form-urlencoded"><fieldset>' 
    + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>' 
    + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>' 
    + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>' 
    + '<div><input id="ListCommits" type="submit" value="List Commits" /></div>' 
    + '</fieldset></form>' 
    + '</body></html>'); 
}).listen(8124); 

console.log('Server running at http://127.0.0.1:8124/'); 
+12

我強烈建議您使用(甚至低級別)框架來構建具有節點的應用程序。我個人使用Express(http://expressjs.com/),但如果您選擇,還有其他選項。除其他外,它將允許您輕鬆處理不同的請求類型和路由以及靜態內容。 – 2013-03-15 08:06:17

+0

查看http://stackoverflow.com/questions/6158933/http-post-request-in-node-js – user568109 2013-03-15 11:00:12

+0

你可以在我的博客http:// hectorcorrea上看到一個關於如何使用Express.js處理HTTP POST的簡單示例.com/blog/introduction-to-node-js – 2013-03-15 13:23:58

回答

129

我會使用你提供的代碼,並提供一個答案比什麼是覆蓋在你的問題,以適應人在遙遠的未來更徹底。我還會提供一個使用「Vanilla JS」(http://www.vanilla-js.com/)的答案,因爲我想太多時髦人士在嘗試學習這種方法時會說「使用框架」。我認爲他們這樣做的原因是因爲有人告訴他們在學習如何工作時「使用框架」。因爲他們不是黑客,他們並不在意嘗試和理解這個過程,所以很多時候他們不知道如何獨立完成這個工作,沒有框架(因此無處不在「使用框架」)。通過了解發生了什麼,你會成爲一個更好的黑客,我希望這個答案能幫助你。

既然您希望通過您輸出的表單接受POST(表單)數據,則需要在您的服務器中提供路由機制。這意味着您會告訴您的服務器將表單提供給訪問您網站的人員,但如果用戶提交表單,Node會將POST數據路由到一個小處理函數。我已經提供了完整的答案,然後將其進一步剖析,以適應想要從代碼學習的人。

var http = require('http'); 
var qs = require('querystring'); 
var formOutput = '<html><body>' 
    + '<h1>XYZ Repository Commit Monitor</h1>' 
    + '<form method="post" action="inbound" enctype="application/x-www-form-urlencoded"><fieldset>' 
    + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>' 
    + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>' 
    + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>' 
    + '<div><input id="ListCommits" type="submit" value="List Commits" /></div></fieldset></form></body></html>'; 
var serverPort = 8124; 
http.createServer(function (request, response) { 
    if(request.method === "GET") { 
    if (request.url === "/favicon.ico") { 
     response.writeHead(404, {'Content-Type': 'text/html'}); 
     response.write('<!doctype html><html><head><title>404</title></head><body>404: Resource Not Found</body></html>'); 
     response.end(); 
    } else { 
     response.writeHead(200, {'Content-Type': 'text/html'}); 
     response.end(formOutput); 
    } 
    } else if(request.method === "POST") { 
    if (request.url === "/inbound") { 
     var requestBody = ''; 
     request.on('data', function(data) { 
     requestBody += data; 
     if(requestBody.length > 1e7) { 
      response.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'}); 
      response.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>'); 
     } 
     }); 
     request.on('end', function() { 
     var formData = qs.parse(requestBody); 
     response.writeHead(200, {'Content-Type': 'text/html'}); 
     response.write('<!doctype html><html><head><title>response</title></head><body>'); 
     response.write('Thanks for the data!<br />User Name: '+formData.UserName); 
     response.write('<br />Repository Name: '+formData.Repository); 
     response.write('<br />Branch: '+formData.Branch); 
     response.end('</body></html>'); 
     }); 
    } else { 
     response.writeHead(404, 'Resource Not Found', {'Content-Type': 'text/html'}); 
     response.end('<!doctype html><html><head><title>404</title></head><body>404: Resource Not Found</body></html>'); 
    } 
    } else { 
    response.writeHead(405, 'Method Not Supported', {'Content-Type': 'text/html'}); 
    return response.end('<!doctype html><html><head><title>405</title></head><body>405: Method Not Supported</body></html>'); 
    } 
}).listen(serverPort); 
console.log('Server running at localhost:'+serverPort); 

而現在的故障解釋了爲什麼我做了我做的事情。

var http = require('http'); 
var qs = require('querystring'); 

首先,您將添加Node的內置'querystring'模塊來解析實際的表單數據。

var formOutput = '<html><body>' 
    + '<h1>XYZ Repository Commit Monitor</h1>' 
    + '<form method="post" action="/inbound" enctype="application/x-www-form-urlencoded"><fieldset>' 
    + '<div><label for="UserName">User Name:</label><input type="text" id="UserName" name="UserName" /></div>' 
    + '<div><label for="Repository">Repository:</label><input type="text" id="Repository" name="Repository" /></div>' 
    + '<div><label for="Branch">Branch:</label><input type="text" id="Branch" name="Branch" value="master" /></div>' 
    + '<div><input id="ListCommits" type="submit" value="List Commits" /></div></fieldset></form></body></html>'; 
var serverPort = 8124; 

我搬到形式輸出了我們上面的服務器/路由/表格處理機制,因爲邏輯是那麼更容易閱讀。我也將服務器端口信息移到這裏,因爲你只需要在一個地方改變它,而不是在下面。

http.createServer(function (request, response) { 

(我通常會縮短這個功能,「請求」和「資源」的參數,不過這只是我的偏好。)

if(request.method === "GET") { 
    if (request.url === "/favicon.ico") { 
     response.writeHead(404, {'Content-Type': 'text/html'}); 
     response.write(notFound); 
     response.end(); 

在這裏,我已經包括了一個簡單的路由實例。在這種情況下,我們讓我們的服務器監聽「favicon.ico」的請求 - 這是幾乎所有主要瀏覽器對網頁的所有初始請求的請求。該文件是您可以在每個訪問的網頁的標籤中看到的小圖標。對於我們的目的,我們不需要提供一個favicon,但我們會處理入站請求,以顯示一些基本的路由機制。

} else { 
     response.writeHead(200, {'Content-Type': 'text/html'}); 
     response.end(formOutput); 
    } 

如果訪問者指向他們的瀏覽器到任何其他資源使用默認的GET方法(除了「favicon.ico的」我們只是上述處理)服務器上,我們會爲他們服務的形式。

} else if(request.method === "POST") { 

否則,如果您的訪問者在你的服務器指向一個帖子,它很可能他們已經提交了他們與以前的GET請求檢索的形式。

if (request.url === "/inbound") { 

在這裏,我們傾聽稱爲「/入內」的入站請求 - 如果你抓住了小細節上面 - 是我們的HTML表單的「動作」。如您所知,表單的「動作」會告訴瀏覽器發送表單數據的位置。

 var requestBody = ''; 
     request.on('data', function(data) { 
     requestBody += data; 
     if(requestBody.length > 1e7) { 
      response.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'}); 
      response.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>'); 
     } 
     }); 
     request.on('end', function() { 
     var formData = qs.parse(requestBody); 

這看起來有點令人困惑,但我保證它不是。 POST請求可以作爲來自客戶端瀏覽器的多部分消息發送。對於表單中幾個變量這樣小的內容,您不可能看到這一點,但隨着您處理的數據量的增加,您會看到這一點。如果您仔細觀察,您還會看到if()聲明詢問POST數據的長度。一個惡意的人可以通過上傳一個無盡的文件來終止你的服務器,但是如果我們採取行動則不會。這會將POST數據正文限制爲大約十兆字節,但您應該相應地進行調整。瞭解這些事情可以防止未來頭痛,我不希望你頭痛。

 response.writeHead(200, {'Content-Type': 'text/html'}); 
     response.write('<!doctype html><html><head><title>response</title></head><body>'); 
     response.write('Thanks for the data!<br />User Name: '+formData.UserName); 
     response.write('<br />Repository Name: '+formData.Repository); 
     response.write('<br />Branch: '+formData.Branch); 
     response.end('</body></html>'); 
     }); 

這裏是我們使用表單數據的地方。由於Javascript的本質,這些變量名稱是CASE SENSITIVE(例如「UserName」而不是「username」)。當然,你可以用這些數據做任何你想要的事情(記住Node的事件循環和異步特性)。

} 
    response.writeHead(404, 'Resource Not Found', {'Content-Type': 'text/html'}); 
    return response.end('<!doctype html><html><head><title>404</title></head><body>413: Request Entity Too Large</body></html>'); 

繼續我們的路由實例,包括我們這裏做一個包羅萬象的下方的if()聲明,向客戶端發送一個通用的404「未找到」回覆任何POST請求,我們還沒有準備好處理。

} else { 
    response.writeHead(405, 'Method Not Supported', {'Content-Type': 'text/html'}); 
    return response.end('<!doctype html><html><head><title>405</title></head><body>405: Method Not Supported</body></html>'); 
    } 
}).listen(serverPort); 
console.log('Server running at localhost:'+serverPort); 

現在我們剛剛完成了代碼,包括一些代碼來處理奇怪方法的請求。有幾件事我沒有解決(功能結構,空表格數據等),但確實有很多方法可以實現您的目標。正如我的許多年前CS教授所說的,有很多方法可以編程,很容易通過分享作業看到誰在作弊。

我希望你(和其他任何人)能夠看到,使用其內置模塊而不是依賴諸如Express之類的外部第三方庫,在Node中執行某些操作並不是一些深奧或甚至稍微困難的過程。這些圖書館在世界上佔有一席之地,但不要追隨羣體:對你的代碼作出明智的決定,因爲在一天結束時,你是負責它的人(不是一些人在堆棧溢出)。

+13

爲什麼我不能高調這10次嗎?;) – Mixthos 2014-03-10 15:43:16

+3

它的思想很重要。謝謝! :) – L0j1k 2014-03-10 21:57:27

+3

很好的回答!非常適合初學:)謝謝! – Martin 2014-03-30 19:41:25