使用ExpressJS提供非标准HTTP方法

时间:2012-02-16 20:51:15

标签: http node.js express

我想编写一个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()使用POST_method=foo请求时,它可以正常运行。但实际的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实现这一点,而不会避免入侵其核心文件。

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

4 个答案:

答案 0 :(得分:4)

简短回答:不,这是不可能的。并非没有实现自己的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模块不会使这些请求可用。

答案 1 :(得分:1)

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

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


mentioned已尝试实施PURGEadded为v0.7.5中的白名单。

答案 2 :(得分:0)

正如其他人所说,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解析器或调整现有的解析器之间进行选择时,我选择在这个实例中进行调整。

答案 3 :(得分:-1)

这有真正重要的目的吗?只有你自己的HTTP服务器和客户端能够相互通信,并且看起来需要付出很大的努力才能获得非常微小的收益。 standard HTTP verbs以什么方式让你失败?

要回答您是否需要入侵Express的问题:需要深入研究。快递requirehttp模块,至少需要用自己的模块覆盖它。 Node.js的内置core modules are always checked first,所以你不能只为你的模块命名。