使用ExpressJS服务非标准的HTTP方法

我想写一个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请求不起作用。 一旦客户端发送请求的第一行,连接就被服务器closures:

 $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模块。

为了testing,启动一个准系统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模块不会使这些请求可用。

节点在C中有一个可接受的HTTP动词的硬编码白名单 。

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


你提到你正试图实施PURGE ,它已经被添加到v0.7.5的白名单中。

这真的有重要的目的吗? 只有你自己的HTTP服务器和客户端才能够相互交stream,而且这似乎是一个很小的收获。 标准HTTP动词以何种方式失败?

要回答你是否需要入侵Express:这需要挖掘到它的问题。 Express require http模块,至less需要用自己的模块覆盖它。 Node.js内置的核心模块总是被首先检查 ,所以你不能只给你的模块同名。

正如其他人所说,Node.js的HTTP服务器库被configuration为只接受特定的动词。 Ben Noordius使用荷兰芹的build议也行不通,因为那个图书馆接受一个更小的动词白名单。 (也有一段时间没有保持。)

在这个阶段,如果我们要支持古怪的要求,就必须采取更激烈的措施。 这里有一个很好的丑陋的黑客攻击,涉及到鸭子内部的一些行为。 这可以在Node.js的v0.10.x上运行,但在新版本可用时请仔细testing。

就我而言,我不仅需要支持非标准动词,还需要支持非标准协议版本标识符以及缺lessIcecast源stream的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]); } }; } 

这是丑陋的,但工程。 我并不特别高兴,但是当在一个粗糙的,从头开始的HTTPparsing器之间进行select或者调整一个现有的parsing器的时候,我select在这种情况下进行调整。