Java 如何处理包含正斜杠 (/) 的请求?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31421061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:05:59  来源:igfitidea点击:

How to handle requests that includes forward slashes (/)?

javaregexspringspring-mvc

提问by Hyman

I need to handle requests as following:

我需要按如下方式处理请求:

www.example.com/show/abcd/efg?name=alex&family=moore   (does not work)
www.example.com/show/abcdefg?name=alex&family=moore   (works)
www.example.com/show/abcd-efg?name=alex&family=moore   (works)

It should accept any sort of character from the value that is located between www.example.com/show/and ?. Please note the value that would be located there would be a single value not name of an action.

它应该接受位于www.example.com/show/和之间的值中的任何类型的字符?。请注意,将位于那里的值将是单个值而不是操作名称。

For example: /show/abcd/efgand /show/lkikf?name=Hymanin which the first request should redirect user to the page abcd/efg(because thats a name) and the second one should redirect user to the page lkikfalong with value of parameter name.

例如:/show/abcd/efg/show/lkikf?name=Hyman其中,所述第一请求应用户重定向到页面abcd/efg(因为这就是一个名称)和第二个应用户重定向到页面lkikf具有参数名的值一起。

I have following controller to handle it but the issue is when I have / in the address the controller is unable to handle it.

我有以下控制器来处理它,但问题是当我在地址中有 / 时控制器无法处理它。

@RequestMapping(value = "/{mystring:.*}", method = RequestMethod.GET)
public String handleReqShow(
            @PathVariable String mystring,
            @RequestParam(required = false) String name,
            @RequestParam(required = false) String family, Model model)     {

I used following regex which did not work.

我使用了以下正则表达式,但它不起作用。

 /^[ A-Za-z0-9_@./#&+-]*$/

采纳答案by Arpit Aggarwal

You have to create two methods then one having the @RequestMapping(value = { "/{string:.+}" })annotation and the other having @RequestMapping(value = { "/{string:.+}", "/{string:.+}/{mystring:.+}" })and then act accordingly in each, because you can't have optional path variables.

您必须创建两种方法,然后一种具有@RequestMapping(value = { "/{string:.+}" })注释,另一种具有@RequestMapping(value = { "/{string:.+}", "/{string:.+}/{mystring:.+}" })然后在每个方法中进行相应操作,因为您不能具有可选的路径变量。

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/show")
public class HelloController {

    @RequestMapping(value = { "/{string:.+}" })
    public String handleReqShow(@PathVariable String string,
            @RequestParam(required = false) String name,
            @RequestParam(required = false) String family, Model model) {
        System.out.println(string);
        model.addAttribute("message", "I am called!");
        return "hello";
    }

    @RequestMapping(value = { "/{string:.+}", "/{string:.+}/{mystring:.+}" })
    public String whatever(@PathVariable String string,
            @PathVariable String mystring,
            @RequestParam(required = false) String name,
            @RequestParam(required = false) String family, Model model) {
        System.out.println(string);
        System.out.println(mystring);
        model.addAttribute("message", "I am called!");
        return "hello";
    }
}

回答by Ankur Jain

The first one is not working because you are trying to handle an entirely new URL which is not actually mapped your controller.

第一个不起作用,因为您正在尝试处理一个全新的 URL,它实际上并未映射到您的控制器。

www.example.com/show/abcd/efg?name=alex&family=moore   (does not work)

The correct mapping for the above URL could be like the below code.

上述 URL 的正确映射可能类似于以下代码。

@RequestMapping(value = {"/{mystring:.*}" , "/{mystring:.*}/{mystring2:.*}"}, method = RequestMethod.GET)
public String handleReqShow(
        @PathVariable String mystring,
        @PathVariable String mystring2,
        @RequestParam(required = false) String name,
        @RequestParam(required = false) String family, Model model)     {

I have tried the similar concept when my one controller is used to handle multiple types of request.

当我的一个控制器用于处理多种类型的请求时,我尝试了类似的概念。

回答by Daniel Newtown

You can define rules to avoid that

您可以定义规则来避免这种情况

<filter>
    <filter-name>UrlRewriteFilter</filter-name>
    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>UrlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

rules.xml add this to your WEB-INF

rules.xml 将此添加到您的 WEB-INF

<urlrewrite>
    <rule>
       <from>^/(10\..*)$</from> <!-- tweak this rule to meet your needs -->
       <to>/Show?temp=</to>
    </rule>
</urlrewrite>

回答by SKalariya

Try escaping forward slash. Regex: /^[ A-Za-z0-9_@.\/#&+-]*$/

尝试转义正斜杠。正则表达式:/^[ A-Za-z0-9_@.\/#&+-]*$/

回答by Master Slave

The default Spring MVC path mapper uses the /as a delimiter for path variables, no matter what.

/无论如何,默认的 Spring MVC 路径映射器都将用作路径变量的分隔符。

The proper way to handle this request would be to write a custom path mapper, that would change this logic for the particular handler method and delegate to default for other handler methods.

处理此请求的正确方法是编写自定义路径映射器,这将更改特定处理程序方法的此逻辑,并将其他处理程序方法委托给默认值。

However, if you know the max possible count of slashes in your value, you can in fact write a handler that accepts optional path variables, and than in the method itself, assemble the value from path variable parts, here is an example that would work for max one slash, you can easily extend it to three or four

但是,如果您知道值中斜线的最大可能数,则实际上可以编写一个接受可选路径变量的处理程序,而不是在方法本身中,从路径变量部分组装值,这是一个可以工作的示例对于最多一个斜线,您可以轻松地将其扩展到三个或四个

@RequestMapping(value = {"/{part1}", "/{part1}/{part2}"}, method = RequestMethod.GET)
public String handleReqShow(
        @PathVariable Map<String, String> pathVariables,
        @RequestParam(required = false) String name,
        @RequestParam(required = false) String family, Model model) {
    String yourValue = "";
    if (pathVariables.containsKey("part1")) {
        String part = pathVariables.get("part1");
        yourValue += " " + part;
    }
    if (pathVariables.containsKey("part2")) {
        String part = pathVariables.get("part2");
        yourValue += " /" + part;
    }
    // do your stuff

}

You can catch all the path variables inside the map, the map @PathVariable Map<String, String> pathVariables, but the downside is that the static part of the mapping has to enumarate all the possible variations

您可以捕获地图中的所有路径变量 map @PathVariable Map<String, String> pathVariables,但缺点是映射的静态部分必须枚举所有可能的变化

回答by Ayan Chakraborty

Another way I do is:

我做的另一种方法是:

@RequestMapping(value = "test_handler/**", method = RequestMethod.GET)

...and your test handler can be "/test_hanlder/a/b/c" and you will get the whole value using following mechanism.

...并且您的测试处理程序可以是“/test_hanlder/a/b/c”,您将使用以下机制获得整个值。

requestedUri = (String) 
request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);

回答by Nikita Kuznetsov

You could encode slashes on UI with %2f: http://www.example.com/show/abcd%2fefg?name=alex&family=moore. Now you should configure Spring to handle slashes. Simple config example:

您可以使用 %2f: 对 UI 上的斜杠进行编码http://www.example.com/show/abcd%2fefg?name=alex&family=moore。现在您应该配置 Spring 来处理斜杠。简单配置示例:

@RestController
public class TestController {

    @GetMapping("{testId:.+}")
    public String test(@PathVariable String testId) {
        return testId;
    }


    @GetMapping("{testId:.+}/test/{messageId}")
    public String test2(@PathVariable String testId, @PathVariable String messageId) {
        return testId + " " + messageId;
    }

    //Only if using Spring Security
    @Configuration
    public static class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
        @Bean
        public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
            DefaultHttpFirewall firewall = new DefaultHttpFirewall();
            firewall.setAllowUrlEncodedSlash(true);
            return firewall;
        }
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
        }
    }


    @Configuration
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public static class SpringMvcConfig extends WebMvcConfigurerAdapter {
        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
            UrlPathHelper urlPathHelper = new UrlPathHelper();
            urlPathHelper.setUrlDecode(false);
            configurer.setUrlPathHelper(urlPathHelper);
        }
    }

}