当前位置:   article > 正文

spirng webUrl常见的集中问题_pathpatternscondition

pathpatternscondition

1,当@PathVariable遇到/

常见的代码是如下图所示

  1. @GetMapping("/hi1/{name}")
  2. public String hello(@PathVariable String name){
  3. return name;
  4. }

如果假设我们的name字段含有/字符是,会怎么样呢,比如lcy/sss,lcysss/,/lcysss是回事什么样子呢?当我们尝试之后就会发现,lcy/sss这种的会报错页面不存在,其他的都会返回lcysss。针对这种情况,我们看一下为什么回事这样?

我们先连接一下url匹配执行方法的相关问题,大致代码过程参考org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod

  1. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
  2. List<Match> matches = new ArrayList<>();
  3. //尝试按照url进行精确匹配
  4. List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
  5. if (directPathMatches != null) {
  6. //精确匹配上,存储匹配结果
  7. addMatchingMappings(directPathMatches, matches, request);
  8. }
  9. if (matches.isEmpty()) {
  10. //如果没有匹配上,尝试根据请求来匹配
  11. addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
  12. }
  13. if (!matches.isEmpty()) {
  14. Match bestMatch = matches.get(0);
  15. if (matches.size() > 1) {
  16. //处理多个匹配的结果
  17. Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
  18. matches.sort(comparator);
  19. bestMatch = matches.get(0);
  20. if (logger.isTraceEnabled()) {
  21. logger.trace(matches.size() + " matching mappings: " + matches);
  22. }
  23. if (CorsUtils.isPreFlightRequest(request)) {
  24. for (Match match : matches) {
  25. if (match.hasCorsConfig()) {
  26. return PREFLIGHT_AMBIGUOUS_MATCH;
  27. }
  28. }
  29. }
  30. else {
  31. Match secondBestMatch = matches.get(1);
  32. if (comparator.compare(bestMatch, secondBestMatch) == 0) {
  33. Method m1 = bestMatch.getHandlerMethod().getMethod();
  34. Method m2 = secondBestMatch.getHandlerMethod().getMethod();
  35. String uri = request.getRequestURI();
  36. throw new IllegalStateException(
  37. "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
  38. }
  39. }
  40. }
  41. request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
  42. handleMatch(bestMatch.mapping, lookupPath, request);
  43. return bestMatch.getHandlerMethod();
  44. }
  45. else {
  46. //匹配不上,直接报错
  47. return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
  48. }
  49. }

然后在仔细看第一步,根据path进行匹配查询

我们可以看到没有匹配上。

 在上面没有精确匹配上,则开始执行模匹配,待匹配的方法可以参考如图:

 显然。hi/{name}这个匹配方法已经出现了带匹配候选中,具体匹配的过程可以参考源码

org.springframework.web.servlet.mvc.method.RequestMappingInfo#getMatchingCondition

  1. public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
  2. //检查http请求方法是否预定义的方法条件匹配
  3. RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
  4. if (methods == null) {
  5. return null;
  6. }
  7. //检查请求参数是否与定义的参数条件匹配
  8. ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
  9. if (params == null) {
  10. return null;
  11. }
  12. //检查请求头部是否与定义的参数条件匹配
  13. HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
  14. if (headers == null) {
  15. return null;
  16. }
  17. //代码检查请求的内容类型是否与定义的consumes条件匹配
  18. ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
  19. if (consumes == null) {
  20. return null;
  21. }
  22. //检查可接收的内容类型是否与定义的produces条件匹配
  23. ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
  24. if (produces == null) {
  25. return null;
  26. }
  27. PathPatternsRequestCondition pathPatterns = null;
  28. //检查请求路径是否与定义的路径模式条件匹配
  29. if (this.pathPatternsCondition != null) {
  30. pathPatterns = this.pathPatternsCondition.getMatchingCondition(request);
  31. if (pathPatterns == null) {
  32. return null;
  33. }
  34. }
  35. PatternsRequestCondition patterns = null;
  36. if (this.patternsCondition != null) {
  37. //检查请求路径是否预定义的模式条件匹配
  38. patterns = this.patternsCondition.getMatchingCondition(request);
  39. if (patterns == null) {
  40. return null;
  41. }
  42. }
  43. //检查用户定义的任何自定义的模式条件匹配
  44. RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
  45. if (custom == null) {
  46. return null;
  47. }
  48. return new RequestMappingInfo(this.name, pathPatterns, patterns,
  49. methods, params, headers, consumes, produces, custom, this.options);
  50. }

上述代码可以看到,匹配会查所有的的信息,如果有一个不匹配,则不符合

3.根据匹配情况返回结果

如果找到匹配的方法,则返回方法,如果没有,则返回null,同时为什么lcysss/,/lcysss没有报错,而是直接拿回了/。这里需要看一下匹配路径的方法:

org.springframework.web.servlet.mvc.condition.PatternsRequestCondition#getMatchingPatterns

public List<String> getMatchingPatterns(String lookupPath) {
   List<String> matches = null;
   for (String pattern : this.patterns) {
      String match = getMatchingPattern(pattern, lookupPath);
      if (match != null) {
         matches = (matches != null ? matches : new ArrayList<>());
         matches.add(match);
      }
   }
   if (matches == null) {
      return Collections.emptyList();
   }
   if (matches.size() > 1) {
      matches.sort(this.pathMatcher.getPatternComparator(lookupPath));
   }
   return matches;
}
  1. private String getMatchingPattern(String pattern, String lookupPath) {
  2. if (pattern.equals(lookupPath)) {
  3. return pattern;
  4. }
  5. if (this.useSuffixPatternMatch) {
  6. if (!this.fileExtensions.isEmpty() && lookupPath.indexOf('.') != -1) {
  7. for (String extension : this.fileExtensions) {
  8. if (this.pathMatcher.match(pattern + extension, lookupPath)) {
  9. return pattern + extension;
  10. }
  11. }
  12. }
  13. else {
  14. boolean hasSuffix = pattern.indexOf('.') != -1;
  15. if (!hasSuffix && this.pathMatcher.match(pattern + ".*", lookupPath)) {
  16. return pattern + ".*";
  17. }
  18. }
  19. }
  20. if (this.pathMatcher.match(pattern, lookupPath)) {
  21. return pattern;
  22. }
  23. if (this.useTrailingSlashMatch) {
  24. if (!pattern.endsWith("/") && this.pathMatcher.match(pattern + "/", lookupPath)) {
  25. return pattern + "/";
  26. }
  27. }
  28. return null;
  29. }

最后会尝试加一下/进行匹配。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/796495
推荐阅读
相关标签
  

闽ICP备14008679号