【问题标题】:Serving non-standard HTTP method with ExpressJS使用 ExpressJS 提供非标准 HTTP 方法
【发布时间】:2012-03-08 07:07:57
【问题描述】:

我想编写一个使用非标准 HTTP 方法(动词)响应请求的 HTTP 服务器。例如,客户端会发出类似FOO / HTTP/.1.1 的请求。在服务器端,此请求将由以下内容处理:

var express = require('express');

var app = express.createServer();

app.configure(function(){
  app.use(express.logger({ format: ':method :url' }));
  app.use(express.methodOverride());
});

app.foo('/', function(req, res){
    res.send('Hello World');
});

app.listen(3000);

我将我的非标准方法附加到 ExpressJS 的 lib/router/methods.js 中导出的数组中。这允许我按预期编写我的服务器代码。当使用express.methodOverride() 和带有_method=fooPOST 请求时,它可以工作。但是实际的FOO 请求不起作用。一旦客户端发送请求的第一行,服务器就会关闭连接:

$telnet localhost 3000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
FOO / HTTP/1.1
Connection closed by foreign host.

我希望能够使用 ExpressJS 实现这一点,并且避免侵入其核心文件。

知道这是否可行以及如何实现?

【问题讨论】:

    标签: http node.js express


    【解决方案1】:

    简短回答:不,这是不可能的。不是没有实现你自己的 HTTP 模块。

    要进行测试,请启动准系统 HTTP 服务器 ...

    $ node
    > require('http').createServer(function(req, res) {
    ...   console.log(req.method);
    ...   res.end();
    ... }).listen(8080);
    

    然后(正如您已经完成的那样)telnet 到它并发出 GET 和 FOO 请求...

    $ telnet localhost 8080
    Trying ::1...
    telnet: connect to address ::1: Connection refused
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    GET / HTTP/1.1
    
    HTTP/1.1 200 OK
    Connection: keep-alive
    Transfer-Encoding: chunked
    
    0
    
    FOO / HTTP/1.1
    Connection closed by foreign host.
    
    $ 
    

    在节点控制台中你会看到

    GET
    

    ...但没有 FOO。因此,Express 使用的节点的本机 HTTP 模块不会使这些请求可用。

    【讨论】:

    • 只是为了发布更新 - 在当前节点 (4.6) 和 express (4) 版本中,您可以处理自定义 HTTP 动词。收听app.all,然后在回调中检查req.method
    • @MatsLindh,你确定吗?在节点 10.11.0 上尝试来自此答案的代码,如果节点的方法未知,它会响应 400。或者我需要指定一些额外的标志?
    • @Qwertiy 如果您有任何问题,请提出一个新问题并添加相关代码。三年后,如果没有您尝试过的信息,就不可能说出来。
    【解决方案2】:

    节点在 C 中有一个 hard-coded whitelist of acceptable HTTP verbs

    为了接受自定义动词,您必须修改 HTTP 解析器并重新编译节点。


    mentioned 正在尝试实现 PURGE,在 v0.7.5 中将 added 添加到白名单中。

    【讨论】:

      【解决方案3】:

      正如其他人所说,Node.js 的 HTTP 服务器库被配置为只接受特定的动词。 Ben Noordius 使用Parsley 的建议也不起作用,因为该库接受的动词白名单更小。 (它也有一段时间没有维护了。)

      在这个阶段,如果我们想支持古怪的请求,我们必须采取更严厉的措施。这是一个很好的丑陋黑客,涉及鸭子打一些内部行为。这适用于 Node.js 的 v0.10.x,但在新版本可用时仔细测试。

      就我而言,我不仅需要支持非标准动词,还需要支持非标准协议版本标识符,以及 Icecast 源流缺少的 Content-Length 标头:

      SOURCE /live ICE/1.0
      

      以下内容应该可以帮助您入门:

      server.on('connection', function (socket) {
          var originalOnDataFunction = socket.ondata;
          var newLineOffset;
          var receiveBuffer = new Buffer(0);
          socket.ondata = function (d, start, end) {
              receiveBuffer = Buffer.concat([receiveBuffer, d.slice(start, end)]);
              if ((newLineOffset = receiveBuffer.toString('ascii').indexOf('\n')) > -1) {
                  var firstLineParts = receiveBuffer.slice(0, newLineOffset).toString().split(' ');
                  firstLineParts[0] = firstLineParts[0].replace(/^SOURCE$/ig, 'PUT');
                  firstLineParts[2] = firstLineParts[2].replace(/^ICE\//ig, 'HTTP/');
                  receiveBuffer = Buffer.concat([
                      new Buffer(
                          firstLineParts.join(' ') + '\r\n' + 
                          'Content-Length: 9007199254740992\r\n'
                      ), 
                      receiveBuffer.slice(newLineOffset +1)
                  ]);
      
                  socket.ondata = originalOnDataFunction;
                  socket.ondata.apply(this, [receiveBuffer, 0, receiveBuffer.length]);
              }
          };
      }
      

      它很丑,但很有效。我对此并不特别满意,但是当在粗略的从头构建的 HTTP 解析器或调整现有的解析器之间进行选择时,我选择在这种情况下进行调整。

      【讨论】:

        猜你喜欢
        • 2013-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-31
        相关资源
        最近更新 更多