小伙伴遇到个问题,某个controller发布的http服务直接访问没问题,通过nginx转发后就报404,此模块其他url访问都正常。。 controller代码如下:Java并发包源码学习系列:ReentrantReadWriteLock读写锁解析
@RequestMapping("/addrExport.spr")
public class AddrExportController
@RequestMapping(params = "method=exportDynamicQueryData")
public void exportDynamicQueryData(HttpServletRequest request, HttpServletResponse response, String downLoadData) {
System.out.println("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh");
.....
}
springboot应用,未配置上下文根。所以此http服务未使用nginx转发时的直接访问地址为:http://localhost:8299/addrExport.spr?method=exportDynamicQueryData
前台ajax调用url:
server { listen 8888; ...... location /portal/space-addr/ { proxy_pass http://localhost:8299/space-addr/;
} ..... }
使用nginx端口访问的url如下,就是此url访问404 http://localhost:8888/portal/space-addr/addrExport.spr?method=exportDynamicQueryData 一阵兵荒马乱,小伙伴发现此url转发到后台的路径为 http://localhost:8299/space-addr/addrExport.spr?method=exportDynamicQueryData 多了一个space-addr 此时有两种方案, 方案1.在controller里@RequestMapping时增加space-addr前缀 方案2.修改nginx映射去掉proxy_pass中多余的前缀,注意红色字体部分去掉了space-addr,见下文:
location /portal/space-addr/ {
proxy_pass http://localhost:8299/;
}

感谢spring的日志输出,偶然搜索发现了如下内容,什么鬼,竟然增加了两个 rescommon/service/callServerFunction相关的requestmapping:一个有space-addr前缀,一个无前缀。。

.NET 云原生架构师训练营(模块二 基础巩固 敏捷开发)--学习笔记
类全文如下:
1 @Configuration 2 public class CommonConfig { 3 4 @Value("${pub.commonservice.prefix}") 5 String prefix; 6 7 @Bean 8 public ResCommonServiceController registerCommonServiceController() { 9 return new ResCommonServiceController(); 10 } 11 12 @Autowired 13 public void registerCommonServerMapping(ResCommonServiceController registerCommonServiceController, RequestMappingHandlerMapping mapping) { 14 String uri = "/rescommon/service/"; 15 RequestMappingInfo requestMappingInfo = RequestMappingInfo.paths(uri).build(); 16 ResRequestMappingHandlerMapping resRequestMappingHandlerMapping = new ResRequestMappingHandlerMapping(mapping, requestMappingInfo); 17 resRequestMappingHandlerMapping.detectHandlerMethods(registerCommonServiceController); 18 if (!("".equals(prefix) || prefix == null || "${pub.commonservice.prefix}".equals(prefix))) { 19 String[] split = prefix.split(","); 20 for (String prefix1 : split) { 21 ResRequestMappingHandlerMapping resRequestMappingHandlerMapping1 = new ResRequestMappingHandlerMapping(mapping, RequestMappingInfo.paths(prefix1 + uri).build()); 22 resRequestMappingHandlerMapping1.detectHandlerMethods(registerCommonServiceController); 23 } 24 } 25 } 26 }这个写法很有趣,第一次见。。自定义的ResRequestMappingHandlerMapping类扩展了spring的RequestMappingHandlerMapping,覆写了detectHandlerMethods方法,在registerMapping时将自定义的url前缀和method上的url做拼接。
1 public class ResRequestMappingHandlerMapping extends RequestMappingHandlerMapping { 2 3 /** 4 * 代理对象 5 */ 6 private RequestMappingHandlerMapping requestMappingHandlerMapping; 7 8 /** 9 * 存放类的RequestMapping信息 10 */ 11 RequestMappingInfo typeMapping; 12 13 public ResRequestMappingHandlerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping, RequestMappingInfo typeMapping) { 14 this.requestMappingHandlerMapping = requestMappingHandlerMapping; 15 this.typeMapping = typeMapping; 16 } 17 18 @Override 19 public void detectHandlerMethods(final Object handler) { 20 if(handler == null){ 21 return; 22 } 23 Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); 24 final Class<?> userType = ClassUtils.getUserClass(handlerType); 25 26 Map<Method, RequestMappingInfo> methods = MethodIntrospector.selectMethods(userType, new MethodIntrospector.MetadataLookup<RequestMappingInfo>() { 27 public RequestMappingInfo inspect(Method method) { 28 try { 29 return getMappingForMethod(method, userType); 30 } 31 catch (Exception ex) { 32 throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); 33 } 34 } 35 }); 36 37 if (logger.isDebugEnabled()) { 38 logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods); 39 } 40 for (Map.Entry<Method, RequestMappingInfo> entry : methods.entrySet()) { 41 Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType); 42 RequestMappingInfo mapping = entry.getValue(); 43 if (typeMapping != null) { 44 mapping = typeMapping.combine(mapping); 45 } 46 requestMappingHandlerMapping.registerMapping(mapping, handler, invocableMethod); 47 } 48 }
至此,谜题解开了,因为公共侧对ResCommonServiceController类做了特殊定制,使其发布的@RequestMapping方法发布了两个http服务。。所以nginx的转发规则带不带前缀都不影响功能使用。。
Redis 设计与实现 10:五大数据类型之有序集合
发表评论