gpt4 book ai didi

javascript - 如何为 express.static 模拟 http.ServerResponse 和 http.IncomingMessage

转载 作者:IT老高 更新时间:2023-10-28 23:10:51 26 4
gpt4 key购买 nike

我在测试自己的路由处理程序时没有遇到任何问题,但在这种情况下,我想测试 express 的静态处理程序。我终其一生都无法弄清楚它为什么会挂起。显然,我缺少一些回调或需要发出一些事件。

我尽量做最小的例子。

var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');

function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;

this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);

this.on('finish', function() {
console.log("finished response");
callback();
});
};

util.inherits(MockResponse, stream.Writable);

MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};

function createRequest(req) {
var emitter = new events.EventEmitter();
req.on = emitter.on.bind(emitter);
req.once = emitter.once.bind(emitter);
req.addListener = emitter.addListener.bind(emitter);
req.emit = emitter.emit.bind(emitter);
return req;
};

describe('test', function() {

var app;

before(function() {
app = express();
app.use(express.static(__dirname));
});

it('gets test.js', function(done) {

var req = createRequest({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);

function responseDone() {
console.log("done");
done();
}

});

});

设置,

mkdir foo
cd foo
mkdir test
cat > test/test.js # copy and paste code above
^D
npm install express
npm install mocha
node node_modules/mocha/bin/mocha --recursive

它只是超时。

我错过了什么?

我还尝试将请求设为可读流。没有变化

var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');

function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;

this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);

this.on('finish', function() {
console.log("finished response");
callback();
});
};

util.inherits(MockResponse, stream.Writable);

MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};

function MockMessage(req) {
stream.Readable.call(this);
var self = this;
Object.keys(req).forEach(function(key) {
self[key] = req[key];
});
}

util.inherits(MockMessage, stream.Readable);

MockMessage.prototype._read = function() {
this.push(null);
};


describe('test', function() {

var app;

before(function() {
app = express();
app.use(express.static(__dirname));
});

it('gets test.js', function(done) {

var req = new MockMessage({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);

function responseDone() {
console.log("done");
done();
}

});

});

我还在挖掘。查看静态服务器内部,我看到它通过调用 fs.createReadStream 创建了一个可读流。它确实有效

var s = fs.createReadStream(filename);
s.pipe(res);

所以试着让我自己工作就好了

  it('test stream', function(done) {
var s = fs.createReadStream(__dirname + "/test.js");
var res = new MockResponse(responseDone);
s.pipe(res);

function responseDone() {
console.log("done");
done();
}
});

我认为这可能与快速等待输入流完成有关,但似乎也不是这样。如果我使用带有响应的模拟输入流,它就可以正常工作

  it('test msg->res', function(done) {
var req = new MockMessage({});
var res = new MockResponse(responseDone);
req.pipe(res);

function responseDone() {
console.log("done");
done();
}
});

任何我可能缺少的见解都会有所帮助

注意:虽然对第 3 方模拟库的建议表示赞赏,但我仍然非常想了解自己缺少什么。即使我最终切换到某个库,我仍然想知道为什么这不起作用。

最佳答案

我发现了两个导致 finish 回调无法执行的问题。

  1. serve-static 使用 send 模块,该模块用于从路径创建文件读取流并将其通过管道传输到 res 对象。但是该模块使用 on-finished 模块检查响应对象中的 finished 属性是否设置为 false,否则 destroys the file readstream .所以文件流永远没有机会发出数据事件。

  2. express initialization覆盖响应对象原型(prototype)。所以像 end() 这样的默认流方法被 http 响应原型(prototype)覆盖:

    exports.init = function(app){
    return function expressInit(req, res, next){
    ...
    res.__proto__ = app.response;
    ..
    };
    };

    为了防止这种情况,我在静态中间件之前添加了另一个中间件,以将其重置回 MockResponse 原型(prototype):

    app.use(function(req, res, next){
    res.__proto__ = MockResponse.prototype; //change it back to MockResponse prototype
    next();
    });

以下是使其与 MockResponse 一起使用所做的更改:

...
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely

//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
};

...
describe('test', function() {

var app;

before(function() {
app = express();

//another middleware to reset the res object
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype;
next();
});

app.use(express.static(__dirname));
});

...

});

编辑:

正如@gman 所指出的,可以使用直接属性而不是原型(prototype)方法。在这种情况下,不需要额外的中间件来覆盖原型(prototype):

function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely

//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);

...

//using direct property for _write, write, end - since all these are changed when prototype is changed
this._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};

this.write = stream.Writable.prototype.write;
this.end = stream.Writable.prototype.end;

};

关于javascript - 如何为 express.static 模拟 http.ServerResponse 和 http.IncomingMessage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32598066/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com