【问题标题】:Access request headers from beforeSave Model Hook从 beforeSave Model Hook 访问请求标头
【发布时间】:2023-03-27 09:50:01
【问题描述】:

如何访问从 Model Hook 提出请求的用户的详细信息

Comment.beforeSave =  function(next,com) {
//Want to add 2 more properties before saving 
com.added_at = new Date();    
com.added_by =  //How can i set the user id here ??
//In case of a Remote hook i have ctx in param and i can get user id like this     ctx.req.accessToken.userId;  But in Model Hook how can i do the same?    
next();    
};

有没有办法做到这一点?我尝试使用远程挂钩来获取主要项目

MainItem.beforeRemote('**', function(ctx, user, next) {   
if(ctx.methodString == 'leave_request.prototype.__create__comments'){       
    ctx.req.body.added_by = ctx.req.accessToken.userId;     
    ctx.req.body.added_at = new Date();                         
    console.log("Added headers as .."+ctx.req.body.added_by);
}    
else{   
    ctx.req.body.requested_at = new Date();
    ctx.req.body.requested_by = ctx.req.accessToken.userId; 
    console.log("Added header @ else as .."+ctx.req.body.requested_by);
}
next();

});

一旦我从资源管理器发出请求,我就会正确获取控制台日志,但是资源管理器总是返回错误

"error": {
    "name": "ValidationError",
    "status": 422,
    "message": "The `comment` instance is not valid. Details: `added_by` can't be blank; `added_at` can't be blank.",
    "statusCode": 422,
    "details": {
      "context": "comment",
      "codes": {
        "added_by": [
          "presence"
        ],
        "added_at": [
          "presence"
        ]
      },
      "messages": {
        "added_by": [
          "can't be blank"
        ],
        "added_at": [
          "can't be blank"
        ]
      }
    },
    "stack": "ValidationError: The `comment` instance is not valid. Details: `added_by` can't be blank; `added_at` can't be blank.\n   "
  }
}

我的模型是这样的

 "properties": {
"body": {
  "type": "string",
  "required": true
},
"added_by": {
  "type": "number",
  "required": true
},
"added_at": {
  "type": "date",
  "required": true
},
"leave_request_id":{
  "type": "number",
  "required": true
}

}

【问题讨论】:

    标签: loopbackjs strongloop


    【解决方案1】:

    您似乎无法通过简单地覆盖ctx.req.body 来更新相关模型。而不是你应该覆盖ctx.args.data - 看起来这个 ctx 参数用于初始化相关模型。

    所以它看起来像这样:

    MainItem.beforeRemote('**', function(ctx, user, next) {   
      if(ctx.methodString == 'leave_request.prototype.__create__comments'){  
         ctx.args.data.added_by = ctx.req.accessToken.userId;     
         ctx.args.data.added_at = new Date();                         
         console.log("Added headers as .."+ctx.args.data.added_by);
      }    
      else{  ... }
      next();
    

    【讨论】:

    • ctx中如何获取操作钩子的请求体?
    【解决方案2】:

    beforeRemote 钩子在模型钩子之前执行,因此您可以将 userId 添加到请求正文中。

    Comment.beforeRemote('**', function (ctx, unused, next) {
        var userId = ctx.req.accessToken.userId;
        if (ctx.methodString == 'Comment.create' || ctx.methodString == 'Comment.updateAttributes') {
            ctx.req.body.userId = userId;
        }
        next();
    });
    

    您可能想查看最适合您的方法字符串。

    【讨论】:

    • 我的 Comment 模型没有直接暴露给 api。所以 beforeRemote 不会为它执行。我的端点是 MainItem//Comment。所以 beforeRemote 只会对 MainItem 执行
    • 在这种情况下,您需要在 MainItem 模型上设置挂钩并尝试将 userId 存储在全局或 Comment 设置中。这不是最佳的,并且可能导致并发请求的错误。对不起。
    【解决方案3】:

    面对同样的问题,我使用了 node expiremantal domain 功能(用于错误处理)。

    保存传入的请求对象:

    // -- Your pre-processing middleware here --
    app.use(function (req, res, next) {
      // create per request domain instance
      var domain = require('domain').create();
    
      // save request to domain, to make it accessible everywhere
      domain.req = req;
      domain.run(next);
    });
    

    在模型钩子中,您可以访问每个连接创建的 req 对象:

    process.domain.req 
    

    StrongLoop 团队还添加了context propagation(基于continuation-local-storage),但尚未记录。

    【讨论】:

      【解决方案4】:

      我通过添加用于正文解析的中间件解决了这个问题。在 middleware.js 我写了以下代码:

      ...
      "parse": {
         "body-parser#json": {},
         "body-parser#urlencoded": {"params": { "extended": true }}
      },
      ...
      

      另外,在 server.js 中,我添加了 body 解析器和 multer 的需求:

      var loopback = require('loopback');
      ...
      var bodyParser = require('body-parser');
      var multer = require('multer');
      ...
      
      app.use(bodyParser.json()); // application/json
      app.use(bodyParser.urlencoded({ extended: true })); // application/x-www-form-urlencoded
      app.use(multer()); // multipart/form-data
      ...
      

      然后在package.json中添加依赖

      "body-parser": "^1.12.4",
      "multer": "^0.1.8"
      

      现在您可以在 /models/user.js 中执行以下操作(适用于任何模型)

        user.beforeRemote('create', function(ctx, unused, next) {
           console.log("The registered user is: " + ctx.req.body.email);
           next();
        });
      

      我希望这会有所帮助! :)

      【讨论】:

        【解决方案5】:

        如果我们假设 User -> Comment 之间存在关系 cmets,您也可以尝试使用关系方法 POST /users/{user_id}/comments 填充 foreignId(可以是 add_by em>)。

        另一件事是add_at。据我了解,验证钩子是在创建钩子之前触发的。这意味着验证将失败,因为该字段在模型中被标记为必需。问题是这个字段是否应该被标记为必填,因为它是由服务器设置的,而不需要由 API 的客户端设置。

        【讨论】:

          猜你喜欢
          • 2018-01-01
          • 1970-01-01
          • 2015-11-13
          • 2019-12-26
          • 1970-01-01
          • 2011-06-18
          • 1970-01-01
          • 1970-01-01
          • 2016-08-08
          相关资源
          最近更新 更多