javascript - 如何在 node.js 中处理 POST 请求

标签 javascript html node.js dom-events

我正在尝试处理发送到我的 node.js 服务器的 post 请求。
名称为 server.js 的 JavaScript 文件在浏览器上显示一个表单。我想在表单值发布到 node.js 后端后访问它们。

该表单包含用户名、存储库和分支。提交表单后,我想将此数据显示回给用户。

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/');

最佳答案

我将使用您提供的代码,并提供比您的问题中涵盖的内容更彻底的答案,以适应遥远的 future 中的人们。我还将提供一个使用“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) {

(我通常将这个函数的参数缩短为“req”和“res”,但这只是我的偏好。)
  if(request.method === "GET") {
    if (request.url === "/favicon.ico") {
      response.writeHead(404, {'Content-Type': 'text/html'});
      response.write(notFound);
      response.end();

这里我包含了一个简单的路由示例。在这种情况下,我们让我们的服务器监听对“favicon.ico”的请求——几乎所有主要浏览器对网页的所有初始请求都会发出这个请求。此文件是您可以在您访问的每个网页的选项卡中看到的小图标。出于我们的目的,我们不需要提供网站图标,但我们将处理它的入站请求以显示一些基本的路由机制。
    } else {
      response.writeHead(200, {'Content-Type': 'text/html'});
      response.end(formOutput);
    }

如果您的访问者使用默认的 GET 方法将他们的浏览器指向您服务器上的任何其他资源(除了我们刚刚处理的“favicon.ico”),我们将为他们提供表单。
  } else if(request.method === "POST") {

否则,如果您的访问者将 POST 指向您的服务器,则他们很可能已经提交了他们通过上一个 GET 请求检索到的表单。
    if (request.url === "/inbound") {

在这里,我们正在监听名为“/inbound”的入站请求——如果你发现了上面的小细节——就是我们 HTML 表单的“ Action ”。您可能知道,表单的“ Action ”告诉浏览器将表单数据发送到何处。
      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 数据主体限制为大约 10 兆字节,但您应该相应地进行调整。了解这些事情可以防止 future 头痛,我不想让你头痛。
        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 的性质,这些变量名称区分大小写(例如“用户名”而不是“用户名”)。当然,你可以对这些数据做任何你想做的事情(记住 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);

现在我们刚刚完成了代码,包括一些用奇怪方法处理请求的代码。有一些事情我没有解决(函数结构、空表单数据等),但确实有很多方法可以实现您的目标。正如我的一位计算机科学教授多年前曾经说过的那样,编写程序的方法有很多种,通过分享他们的作业很容易看出谁在作弊。

我希望您(和其他任何人)可以看到,使用 Node 的内置模块而不是依赖外部第三方库(如 Express)在 Node 中做事并不是什么深奥的,甚至是有点困难的过程。这些库在世界上占有一席之地,但不要随波逐流:对您的代码做出明智的决定,因为归根结底,您是负责它的人(而不是 Stack Overflow 上的某些人)。

关于javascript - 如何在 node.js 中处理 POST 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15427220/

相关文章:

javascript - 如何使用 JavaScript 库使用椭圆曲线解密加密消息?

php - jQuery 选项卡 - jquery 脚本仅适用于第一个选项卡 - 初始化错误?

javascript - 使用jquery根据本地存储数据动态创建HTML分区

在输入表单标记中使用 onclick 属性时 JavaScript 未捕获引用错误

html - 在 css 中,是否可以捕获属性值以在同一个选择器中重用?

javascript - Electron 如何将数据从 Node 重定向到 Angular 7

javascript - 解决 Node.js 类初始化器上的回调 hell

javascript - 是否可以将自定义属性/属性注入(inject) native Web 组件?

javascript - 如何使用 ng-click Controller 功能动态更改 ng-model

javascript - 制作 "Mark all"按钮