Grails 3.1.16 拦截器不过滤方法

Grails 3.1.16 Interceptors not filtering on method

我正在尝试使用 Grails 拦截器来匹配具有特定 HTTP 方法的特定 uri。然而,尽管我将我的 Grails 版本从 3.1.1 升级到 3.1.16, where that issue should be fixed.

,但 match 方法的方法参数被忽略了

我的代码的简化版本是:

@GrailsCompileStatic
class MyInterceptor {

    int order = HIGHEST_PRECEDENCE

    MyInterceptor () {
        match(uri: '/api/domain/*', method: 'PUT')
        match(uri: '/api/domain/*', method: 'DELETE')
        match(uri: '/api/domain/*', method: 'POST')
    }
}

使用以下拦截器测试:

@TestFor(MyInterceptor)
class MyInterceptorSpec extends Specification {

    @Unroll
    def "it matches '#method #uri'"() {
        when: "A request matches the interceptor"
        withRequest(uri: uri, method: method)

        then:"The interceptor does match"
        interceptor.doesMatch()

        where:
        uri             | method
        '/api/domain/1' | 'PUT'
        '/api/domain/1' | 'POST'
        '/api/domain/1' | 'DELETE'
    }

    @Unroll
    def "it does not match '#method #uri'"() {
        when:
        withRequest(uri: uri, method: method)

        then:
        !interceptor.doesMatch()

        where:
        uri             | method
        '/api/domain'   | 'GET'
        '/api/domain/1' | 'GET' // failing test
    }

}

如何确保拦截器仅针对给定的 HTTP 方法匹配 uris?

在 Grails 中默认是不可能的。

查看UrlMappingMatcher的代码我们可以看到,当我们用uri定义匹配规则时,方法部分被忽略了:

@Override
Matcher matches(Map arguments) {
    if(arguments.uri) {
        uriPatterns << arguments.uri.toString()
    }
    else {
        controllerRegex = regexMatch( arguments, "controller")
        actionRegex = regexMatch( arguments, "action")
        namespaceRegex = regexMatch( arguments, "namespace")
        methodRegex = regexMatch( arguments, "method")
    }
    return this
}

@Override
Matcher excludes(Map arguments) {
    if(arguments.uri) {
        uriExcludePatterns << arguments.uri.toString()
    }
    else {
        def exclude = new MapExclude()
        exclude.controllerExcludesRegex = regexMatch( arguments, "controller", null)
        exclude.actionExcludesRegex = regexMatch( arguments, "action", null)
        exclude.namespaceExcludesRegex = regexMatch( arguments, "namespace", null)
        exclude.methodExcludesRegex = regexMatch( arguments, "method", null)
        excludes << exclude
    }
    return this
}

然而,您可以创建 UrlMappingMatcher 的子类,即使在定义了 uri 时也考虑了该方法,并在您的拦截器中使用它而不是常规方法:

// in MyInterceptor.groovy
Matcher match(Map arguments) {
    // use your own implementation of the UrlMappingMatcher
    def matcher = new MethodFilteringUrlMappingMatcher(this)
    matcher.matches(arguments)
    matchers << matcher
    return matcher
}