在过滤器中访问 request.JSON 后 Grails 2.5.0 控制器命令对象绑定

Posted

技术标签:

【中文标题】在过滤器中访问 request.JSON 后 Grails 2.5.0 控制器命令对象绑定【英文标题】:Grails 2.5.0 controller command object binding after accessing request.JSON in a filter 【发布时间】:2015-10-15 17:28:46 【问题描述】:

在 Grails 2.5.0 控制器操作方法中,如果在过滤器中访问了 request.JSON,则 HTTP JSON 正文中的属性似乎不会用于命令对象绑定。

这是为什么呢?这对我来说没有任何意义。

有什么方法可以让request.JSON 在过滤器中使用,也可以用于命令对象绑定?

【问题讨论】:

【参考方案1】:

是的,这是 Grails 在与请求正文进行数据绑定时的默认行为。当您在过滤器中通过request.JSON 读取请求正文时,相应的输入流将被关闭或变为空。因此,现在 Grails 无法进一步访问该请求主体以绑定到命令对象。

因此,您可以在过滤器中自行访问请求正文,也可以将其与命令对象一起使用,但不能同时使用。

来自将请求正文绑定到命令对象标题http://grails.github.io/grails-doc/2.5.0/guide/theWebLayer.html#dataBinding:

请注意,正在解析请求的主体以使其正常工作。 此后任何读取请求正文的尝试都将失败,因为 相应的输入流将为空。控制器动作 可以使用命令对象,也可以解析 自行请求(直接或通过引用类似 request.JSON),但不能两者都做。

所以,你想要实现的目标是不可能直接实现的。但是,你可以做一些不同的事情。在您的过滤器中,读取传入的请求正文并存储到paramssession(如果过滤器将请求传递给控制器​​)​​,然后手动绑定参数:

MyFilters.groovy

class MyFilters 

    def filters = 
        foo(/* your filter */) 
            before = 
                // Your checks
                Map requestData = request.JSON as Map
                session.requestData = requestData
                return true
            
        
    

现在,在您的控制器操作中,不要这样做:

class MyController 

    def fooAction(MyCommandObject object) 
    

做这样的事情:

class MyController 

    def fooAction() 
        MyCommandObject object = new MyCommandObject(session.requestData)
        // Clear from session to clear up the memory
        session.requestData = null
    

更新:我提供的上述解决方案效果很好,但不干净。 @JoshuaMoore 提供了一个更清洁的解决方案的链接Http Servlet request lose params from POST body after read it once。

【讨论】:

虽然这可能有效,但它不是一个可以很好扩展的解决方案。鉴于会话数据的使用,并且您永远不会从会话中清除数据。最好使用实现/扩展HttpServletRequestWrapper 的 Servlet 过滤器以进行可重复阅读。这个主题在 *** 上得到了很好的介绍:***.com/questions/10210645/… ... 仅仅因为某些东西有效,并不意味着它会运作良好。所以,对于一个爱好项目,这里的答案很好,但对于现实世界的应用程序来说,这是短视的。 感谢@JoshuaMoore 的回复。您提供的链接很棒。几个月前我试过这个,但由于时间不够,没有成功。是的,这是我作为临时快速修复解决方案提供的更清洁的解决方案。 您确认如果在过滤器中访问request.JSON,则不会填充命令对象,但我不完全理解为什么会这样。如果我没记错的话,我仍然能够在一个操作方法中从request.JSON 中读取属性,因为request.JSON 是在过滤器中访问的,所以它的命令对象没有被填充。如果所有 JSON 属性仍在 request.JSON 中,为什么 Grails 不使用它来填充命令对象。 另外,鉴于当前的行为,任何人都不应该使用命令对象。如果你编写一个动作方法,你永远无法控制是否有人会使用访问request.JSON 的过滤器。这是一个总是等待发生的巨大错误。鉴于命令对象的限制,Grails 根本不应该支持它们(或者它们应该被修改为独立于过滤器行为)。 如果您已经在过滤器中阅读了request.JSON,我不确定您是否能够在操作中访问它。因为它是通过实现 Java 的 ServletInputStream 来实现的,它在读取时会自动关闭,因为它正在实现 AutoCloseable。因此,这不是 Grails 实现。虽然,Grails 应该按照上面 *** 链接中描述的方式处理这个问题,以便顺利工作。

以上是关于在过滤器中访问 request.JSON 后 Grails 2.5.0 控制器命令对象绑定的主要内容,如果未能解决你的问题,请参考以下文章

链接到 SQL Server 的访问显示 #Name?在过滤后的字段中

有没有办法强制 Oracle 在加入访问后评估过滤器?

使用 Grails 在服务器端获取 JSON 数据

瓶子 request.json 在帖子中获得 405

访问数据库后更改 DOM

django模板:过滤后的点