子类化、扩展或包装 Node.js 'request' 模块以增强响应

Subclassing, extending or wrapping Node.js 'request' module to enhance response

我正在尝试扩展 request 以劫持和增强其 response 和其他 'body' 参数。最后,我想为我的 API:

添加一些方便的方法
var myRequest = require('./myRequest');
myRequest.get(function(err, hijackedResponse, rows) {
    console.log(hijackedResponse.metadata)
    console.log(rows)
    console.log(rows.first)
});

根据 inherits 上的 Node 文档,我认为我可以让它工作(并且使用文档中的 EventEmitter 示例工作正常)。我尝试使用@Trott 的建议让它工作,但意识到对于我的用例它可能无法工作:

// myRequest.js
var inherits = require('util').inherits;
var Request = require("request").Request;

function MyRequest(options) {
    Request.call(this, options);
}

inherits(MyRequest, Request);

MyRequest.prototype.pet = function() {
    console.log('purr')
}

module.exports = MyRequest;

我也一直在玩extend,希望我能找到一种方法来拦截请求的onRequestResponse原型方法,但是我画的是空白:

var extend = require('extend'),
    request = require("request")

function myResponse() {}

extend(myResponse, request)

// maybe some magic happens here?

module.exports = myResponse

最后:

var extend = require('extend'),
    Ok = require('objectkit').Ok

function MyResponse(response) {
    var rows = Ok(response.body).getIfExists('rows');
    extend(response, {
        metadata: extend({}, response.body),
        rows: rows
    });
    response.first = (function() {
        return rows[0]
    })();
    response.last = (function() {
        return rows[rows.length - 1] || rows[0]
    })();
    delete response.metadata.rows
    return response;
}

module.exports = MyResponse

请记住,在这个例子中,我作弊并将其全部写在 .get() 方法中。在我最终的包装器模块中,我实际上将 method 作为参数。

已更新以回答编辑后的问题:

这是您 myResponse.js 内容的粗略模板。它只实现 get()。但作为一个简单的骨头,这就是如何完成这种事情的演示,我希望它能让你继续。

var request = require('request');

var myRequest = {};

myRequest.get = function (callback) {
    // hardcoding url for demo purposes only
    // could easily get it as a function argument, config option, whatever...
    request.get('http://www.google.com/', function (error, response, body) {
        var rows = [];
        // only checking error here but you might want to check the response code as well
        if (!error) {
            // mess with response here to add metadata. For example...
            response.metadata = 'I am awesome';

            // convert body to rows however you process that. I'm just hardcoding.
            // maybe you'll use JSON.parse() or something.
            rows = ['a', 'b', 'c'];

            // You can add properties to the array if you want.
            rows.first = 'I am first! a a a a';
        }

        // now fire the callback that the user sent you...
        callback(error, response, rows);
    });
};

module.exports = myRequest;

原始答案:

查看 the source code for the Request constructor,它需要一个 options 对象,而该对象又需要一个 uri 属性。

所以你需要在你的call()中指定这样一个对象作为第二个参数:

Request.call(this, {uri: 'http://localhost/'});

您可能不想像在构造函数中那样硬编码 uri。您可能希望代码看起来更像这样:

function MyRequest(options) {
    Request.call(this, options);
}

...

var myRequest = new MyRequest({uri: 'http://localhost/'});

要让您的代码正常工作,您还需要将 util.inherits() 移动到 MyRequest.prototype.pat() 的声明上方。 util.inherits() 似乎破坏了第一个参数的任何现有原型方法。