我想编写一个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实现这一点,而不会避免入侵其核心文件。
知道这是否可能以及如何实现?
答案 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)
答案 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的问题:将需要深入研究。快递require
是http
模块,至少需要用自己的模块覆盖它。 Node.js的内置core modules are always checked first,所以你不能只为你的模块命名。