2013-03-15 206 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