返回顶部
首页 > 资讯 > 精选 >怎么对@PathVariable中的特殊字符进行处理
  • 926
分享到

怎么对@PathVariable中的特殊字符进行处理

2023-06-06 13:06:34 926人浏览 薄情痞子
摘要

这期内容当中小编将会给大家带来有关怎么对@PathVariable中的特殊字符进行处理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。 @GetMapping(value="/user/

这期内容当中小编将会给大家带来有关怎么对@PathVariable中的特殊字符进行处理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

 @GetMapping(value="/user/{useraccount}") public void getUserAccount(@PathVariable("useraccount") String userAccount) {  logger.info("useraccount :" + userAccount); }

正常访问:

/user/zhangsan

打印:useraccount : zhangsan

看似一切正常

but:

访问:/user/zhangsan/lisi

打印:useraccount : zhangsan

咦,为啥不是useraccount :zhangsan/lisi ?

@PathVariable并没有我们想象的聪明,对于参数中的/并不能跟实际路径/分开

事实上,有. ; -等都不能正确切分。

怎么办呢?

两种方案:

1,简单点,直接使用@RequestParam代替

 @GetMapping(value="/user") public void getUserAccount(@RequestParam("useraccount") String userAccount) {  logger.info("useraccount :" + userAccount); }

用/user?useraccount=zhangsan 访问

2,使用正则过滤

 @GetMapping(value="/user/{useraccount:[a-zA-Z0-9\\.\\-\\_\\;\\\]+}") public void getUserAccount(@PathVariable("useraccount") String userAccount) {  logger.info("useraccount :" + userAccount); }

正常访问:

/user/zhangsan

打印:useraccount : zhangsan

当然,这个就有点不灵活了,第一种简单又方便

补充:记一次@PathVariable特殊参数会丢失的排查问题

请求参数中如果包含.,会造成参数丢失,请看如下代码

以下代码,省略@RestController控制层类代码

@RequestMapping(value = "hello/{name}")public Map<String, Object> sayHello(@PathVariable("name") String name, httpservletRequest request) { Map<String, Object> rtnMap = new HashMap<>(); rtnMap.put("msg", "hello " + name); return rtnMap;}

请求地址: hello/ddf,则正常返回{"msg": "hello ddf"}

请求地址: hello/ddf.com,依然还是返回{"msg": "hello ddf"}

如果需要解决上面这个问题,则可以将代码更改如下(该解决方式从网上搜寻)

@RequestMapping(value = "hello/{name:.*}")public Map<String, Object> sayHello(@PathVariable("name") String name, HttpServletRequest request) { Map<String, Object> rtnMap = new HashMap<>(); rtnMap.put("msg", "hello " + name); return rtnMap;}

如果使用@PathVariable以.sh或.bat等特殊字符结尾,会影响实际返回数据

报错如下:

{ "timestamp": 1541405292119, "status": 406, "error": "Not Acceptable", "exception": "org.springframework.WEB.HttpMediaTypeNotAcceptableException", "message": "Could not find acceptable representation", "path": "/HDOrg/user/hello/ddf.sh"}

还是上面的代码

以下代码,省略@RestController控制层类代码

@RequestMapping(value = "hello/{name:.*}")public Map<String, Object> sayHello(@PathVariable("name") String name, HttpServletRequest request) { Map<String, Object> rtnMap = new HashMap<>(); rtnMap.put("msg", "hello " + name); return rtnMap;}

如果这时候请求地址为hello/ddf.sh或hello/ddf.com.sh,只要是以.sh结尾,这时候业务逻辑代码不会受到影响,但走到Spring自己的代码去处理返回数据的时候,有一个功能会根据扩展名来决定返回的类型,而以.sh结尾扩展名为sh,会被解析成对应的Content-Type: application/x-sh。

解决办法如下,第一种方法是从网上找到的,可以直接禁用该功能,但有可能会影响到静态资源的访问,不能确定,也没有进行尝试

@Configurationpublic class Config extends WebmvcConfigurerAdapter { @Override public void configureContentNeGotiation(  ContentNegotiationConfigurer configurer) { configurer.favorPathExtension(false); }}

然后以下就是闲着没事很想换个思路尝试去看看这到底是怎么回事,由于个人能力有限,不保证以下内容的重要性;

第二种方式解决思路是,既然扩展名以.sh等结尾会有问题,那么能不能不要让程序将扩展名识别为.sh,或者干脆就跳过处理,比如我是否可以加个.sh/这样就会影响到实际的扩展名,但是又不会影响到已有的代码,其实这里有个偷懒的写法,可以直接在@RequestMapping里的value最后直接加一个/,但是这要求客户端必须在原有的条件上最终拼一个/,否则会找不到对应的映射,直接404,我这里碰到这个问题的时候,因为该方法已经上线并且被其它几个系统调用,因此更改起来会有些繁琐,所以寻求了一种麻烦的方式,先将解决方式放在下面,不确定是否会影响其它问题

这种方式解决方式如下:注释中的两行代码二选一都可,推荐前面的写法,直接已经跳过

@RequestMapping(value = "hello/{name:.*}")public String sayHello(@PathVariable("name") String name) { // 该方法跳过通过上面描述的那种方式来确定MediaType request.setAttribute(PathExtensionContentNegotiationStrategy.class.getName() + ".SKIP", true); // 后面参数的值前半部分必须和该方法的RequestMapping一致,否则无效,不包括ContextPath request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/hello/" + name + "/"); return "hello " + name;}

下面依赖源码来看一下为什么可以这么去做,先看一下为什么会造成这个结果?以下步骤只关心与当前问题有关的部分,并只大概关注其中问题,不作细节的深入

经过debug可以看到错误是在处理以下过程报错,首先如下

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { @Override public void handleReturnValue(Object returnValue, MethodParameter returnType,  ModelAndViewContainer mavContainer, NativeWebRequest webRequest)  throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }}

出现这个问题,一般的查找思路就是是否是请求或响应的Content-Type是否出现了问题,那么在上面这个方法上无论是inputMessage还是outputMessage都是正常的,重点来看一下writeWithMessageConverters()方法,该方法,部分代码如下

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver implements HandlerMethodReturnValueHandler { @SuppressWarnings("unchecked") protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,       ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { Object outputValue; Class<?> valueType; Type declaredType; if (value instanceof CharSequence) {  outputValue = value.toString();  valueType = String.class;  declaredType = String.class; } else {  outputValue = value;  valueType = getReturnValueType(outputValue, returnType);  declaredType = getGenericType(returnType); } HttpServletRequest request = inputMessage.getServletRequest(); List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request); List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType); // 后面处理MediaType的部分在这里全部省略 }    protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, Type declaredType) { Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); if (!CollectionUtils.isEmpty(mediaTypes)) {  return new ArrayList<MediaType>(mediaTypes); } else if (!this.allSupportedMediaTypes.isEmpty()) {  List<MediaType> result = new ArrayList<MediaType>();  for (HttpMessageConverter<?> converter : this.messageConverters) {  if (converter instanceof GenericHttpMessageConverter && declaredType != null) {   if (((GenericHttpMessageConverter<?>) converter).canWrite(declaredType, valueClass, null)) {   result.addAll(converter.getSupportedMediaTypes());   }  }  else if (converter.canWrite(valueClass, null)) {   result.addAll(converter.getSupportedMediaTypes());  }  }  return result; } else {  return Collections.singletonList(MediaType.ALL); } }}

先看方法getAcceptableMediaTypes(),是根据请求来决定当前的HttpServletRequest到底是要请求什么类型的数据,该方法调用链在后面说明;

getProducibleMediaTypes()方法返回可以生成的MediaType,能够生成哪些是看当前项目一共有多少可以被支持的MediaType,当然也能看到也可以通过HttpServletRequest明确设置属性HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE来确定用哪种方式;

拿到这两个列表后,需要判断requestedMediaTypes是否兼容producibleMediaTypes,如* public static final String ALL_VALUE = "**,该方法往下调用部分代码如下:

public class ContentNegotiationManager implements ContentNegotiationStrategy, MediaTypeFileExtensionResolver {  @Override public List<MediaType> resolveMediaTypes(NativeWebRequest request) throws HttpMediaTypeNotAcceptableException { for (ContentNegotiationStrategy strategy : this.strategies) {  List<MediaType> mediaTypes = strategy.resolveMediaTypes(request);  if (mediaTypes.isEmpty() || mediaTypes.equals(MEDIA_TYPE_ALL)) {  continue;  }  return mediaTypes; } return Collections.emptyList(); }}

调用如下:

public class WebMvcAutoConfiguration { @Override public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {  private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class  .getName() + ".SKIP";  Object skip = webRequest.getAttribute(SKIP_ATTRIBUTE,      RequestAttributes.SCOPE_REQUEST); if (skip != null && Boolean.parseBoolean(skip.toString())) {  return Collections.emptyList(); } return this.delegate.resolveMediaTypes(webRequest); }}

在这里可以看到有一个属性为skip,如果它的属性为PathExtensionContentNegotiationStrategy的类全名+".SKP"并且它的值为true,那么这里则不继续往下处理直接返回空的集合,而在前面也已经看到如果返回的空的集合,实际上最终返回给调用方的是**是可以匹配任何生成的producibleMediaTypes,所以最终结果能够按照原先应该返回的类型正确返回,而不会被.sh等后缀影响到;

其实最初没有看到skip的时候,看到了一些后面的代码,最终也解决了这个问题,不论正确与否,先把整个过程记录下来,假如在上面的步骤中没有设置skip=true,那么程序继续下去的部分走向如下

如果uid以.sh结尾的话,在逻辑处理完成之后框架处理return数据的时候,会根据扩展名来决定返回的content-type,sh结尾

会影响返回的content-type为application/x-sh,这会影响该方法的实际功能,解决办法是:

要么禁用该功能,要么修改该方法的@RequestMapping,禁用不能确定是否会对直接访问的静态资源有影响,

而且该方法调用方项目已上线,不宜轻易修改,只能这里改变这个属性的地址,影响框架

后面获取请求的后缀为null,而避免这个问题,但尚不能确认requestUrl和mappingUrl不一致是否会有别的问题

request.setAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE, "/user/" + uid + "/");

上述就是小编为大家分享的怎么对@PathVariable中的特殊字符进行处理了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网精选频道。

--结束END--

本文标题: 怎么对@PathVariable中的特殊字符进行处理

本文链接: https://lsjlt.com/news/247170.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 怎么对@PathVariable中的特殊字符进行处理
    这期内容当中小编将会给大家带来有关怎么对@PathVariable中的特殊字符进行处理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。 @GetMapping(value="/user/...
    99+
    2023-06-06
  • 如何进行MYSQL特殊字符的处理
    这篇文章给大家介绍如何进行MYSQL特殊字符的处理,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。单引号,以及行尾的斜杠引起的困惑:这一次的问题,我们直接从实际的工作中说起:工作内容简介...
    99+
    2024-04-02
  • java项目中怎么对特殊字符进行校验
    这期内容当中小编将会给大家带来有关java项目中怎么对特殊字符进行校验,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1.关于Character.UnicodeBlock的介绍CJK的意思是“Chinese...
    99+
    2023-05-31
    java ava 目中
  • linux终端对特殊字符怎么处理
    在Linux终端中,特殊字符通常由反斜杠(\)进行转义处理。以下是一些常见的特殊字符及其转义方式:1. 反斜杠(\):需要使用两个反...
    99+
    2023-09-05
    linux
  • Oracle怎么处理VARCHAR列中的特殊字符
    在Oracle中处理VARCHAR列中的特殊字符,可以使用函数或者字符串替换的方法来处理。下面是一些常用的方法: 使用REPLAC...
    99+
    2024-04-09
    Oracle
  • python处理http请求中特殊字符(
    直接看代码吧# encoding:utf-8from urllib.parse import quoteimport urllib.requestimport stringimport jsonurl = quote('http://tes...
    99+
    2023-01-31
    特殊字符 python http
  • linux终端对特殊字符的处理方法是什么
    在Linux终端中,特殊字符通常由转义字符来进行处理。转义字符是以反斜杠(\)开头的字符,用于表示特殊含义的字符。以下是常见的特殊字...
    99+
    2023-09-16
    linux
  • Python处理mysql特殊字符的问题
    有的时候我们会去扫表,然后拿出扫的结果再到另一张表里去查信息。比如下面一段 index_sql_str = "select %s from user where %s = %d" % ("so...
    99+
    2022-05-17
    Python mysql 特殊字符
  • PHP对表单提交特殊字符的过滤和处理
    函数名 释义 介绍htmlspecialchars将与、单双引号、大于和小于号化成HTML格式&转成&amp; "转成&quot;' 转成&#0...
    99+
    2024-04-02
  • SqlServer中模糊查询对于特殊字符的处理方法是什么
    SqlServer中模糊查询对于特殊字符的处理方法是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。今天在处理sql查询的时候遇到了li...
    99+
    2024-04-02
  • oracle中怎么转义特殊字符
    本篇文章为大家展示了oracle中怎么转义特殊字符,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。关键词: oracle    转义&n...
    99+
    2024-04-02
  • php字符串中怎么转义成特殊字符
    这篇文章主要介绍php字符串中怎么转义成特殊字符,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!php是什么语言php,一个嵌套的缩写名称,是英文超级文本预处理语言(PHP:Hypertext Preprocessor...
    99+
    2023-06-14
  • python怎么删除字符串的特殊字符
    本篇内容主要讲解“python怎么删除字符串的特殊字符”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python怎么删除字符串的特殊字符”吧!说明strip()删除字符串前后(左右两侧)的空格或...
    99+
    2023-06-20
  • java特殊字符转义处理的方法是什么
    在Java中,可以使用反斜杠(\)来转义特殊字符。以下是一些常见的特殊字符转义序列:- \n:换行- \t:制表符- \r:回车- ...
    99+
    2023-08-11
    java
  • java怎么替换带特殊字符的字符串
    在Java中,可以使用字符串的`replace()`方法来替换带特殊字符的字符串。`replace()`方法接受两个参数,第一个参数...
    99+
    2023-08-16
    java
  • Golang中怎么转义常见的特殊字符
    这篇文章主要介绍了Golang中怎么转义常见的特殊字符的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang中怎么转义常见的特殊字符文章都会有所收获,下面我们一起来看看吧。转义字符在Golang中,转义字符...
    99+
    2023-07-05
  • oracle怎么去掉字段中的特殊符号
    要去掉字段中的特殊符号,可以使用Oracle的REGEXP_REPLACE函数来实现。以下是一个示例SQL语句,将字段中的特...
    99+
    2024-04-09
    oracle
  • html特殊字符编码对照表是怎样的
    本篇文章为大家展示了html特殊字符编码对照表是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。 代码如下:<!DOCTYPE...
    99+
    2024-04-02
  • C#中怎么对字符进行转义
    本篇文章给大家分享的是有关C#中怎么对字符进行转义,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。C#转义字符 C#转义字符的意义\n   回车换行\t 横向跳到下一制表位置\v...
    99+
    2023-06-18
  • PHP7中对十六进制字符串怎么处理
    这篇文章主要讲解了“PHP7中对十六进制字符串怎么处理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PHP7中对十六进制字符串怎么处理”吧!具体问题:$t1 = 0...
    99+
    2023-06-21
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作