君樨 2021-12-16 12:58 采纳率: 50%
浏览 167
已结题

springboot 重定向url变乱

springboot请求访问springboot接口,参数为另外一个url,url中含有# ,
springboot中获得参数时无法获得#和#后面部分;
例如
http://ip/SvgHome.html#/compiles


        TokenData body = restTemplate.getForEntity(URL, TokenData.class).getBody();
        assert body != null;
        log.info(body.getResult());

        String param=url+"&token="+body.getResult();
        log.info(param);
        modelAndView.setViewName("redirect:"+param);
        return modelAndView;

实际跳转路径为http://ip:9143/SvgHome.html&token=aece153ba6b16a1b#/compiles

即把token部分拼接在中间了

查了写资料,说是#的缘故,但是不知道怎么处理,
上面那个问题不会的,解决下面这个也行,

springboot获得参数中包含#的部分,网上说配置tomcatconfig,但是我这个不管用

  • 写回答

8条回答 默认 最新

  • 程序猿麦小七 2021-12-16 14:49
    关注

    最近在项目中遇到了一个问题,需求变更要求,url中需要支持特殊字符,例如:“.”,“@”等。由于项目中包含了很多已经开放的接口,采用的是restful风格的,因此改接口方案直接被pass。在查找了很多资料,最终解决这个问题。

    问题主要包括三个:

    包含特殊url请求时,@ResponseBody 注解的请求,返回时会抛出异常
    如何匹配包含特殊字符的url,例如/email/huang@gmail.com
    采用注解方式自定义异常以json格式返回的,在包含特殊Url时,无法抛出自己想要的异常格式
    注意:本文spring boot版本是基于1.5.16 (2.0以后可能有所不同)

    问题一:包含特殊url请求时,@ResponseBody 注解的请求,返回时会抛出异常
    package com.example.demo.controller;

    import com.example.demo.domain.RestfulAPIResponse;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;

    /**

    • @author huangyichun

    • @date 2018/12/29

    • /
      @RestController
      public class EmailController {

      @GetMapping("/user/{name}")
      public RestfulAPIResponse queryUser(@PathVariable("name") String name) {

        RestfulAPIResponse<String> restfulAPIResponse = new RestfulAPIResponse<>("requestId");
        restfulAPIResponse.setRequestId("requestId");
        restfulAPIResponse.setResult("name", name);
        return restfulAPIResponse;
      

      }
      }

    public class RestfulAPIResponse implements Serializable {

    private String requestId;
    
    private Map<String,R> result;
    
    public RestfulAPIResponse(String requestId){
        result = new HashMap<String,R>();
        this.requestId = requestId;
    }
    
    public String getRequestId() {
        return requestId;
    }
    
    public void setRequestId(String requestId) {
        this.requestId = requestId;
    }
    
    
    public Map getResult() {
        return result;
    }
    
    public void setResult(String key,R value) {
        this.result.put(key,value);
    }
    
    public void setResultMap(Map<String, R> map) {
        if (map != null && map.size() > 0) {
            result.putAll(map);
        }
    }
    

    }

    请求 url : http://127.0.0.1:8080/user/huangyichun_@.com 返回值如下:

    {
    "timestamp": 1546072805982,
    "status": 406,
    "error": "Not Acceptable",
    "exception": "org.springframework.web.HttpMediaTypeNotAcceptableException",
    "message": "Could not find acceptable representation",
    "path": "/user/huangyichun_@.com"
    }
    这个问题是由于使用外部Tomcat导致的,如果直接调用Spring boot的main方法启动的内部tomcat不会产生这个问题。

    解决方法:添加如下配置,问题解决

    package com.example.demo;

    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

    /**

    • @author huangyichun

    • @date 2018/12/29

    • /
      @Configuration
      public class SpringServiceConfiguration extends WebMvcConfigurationSupport {

      @Override
      public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

       // to  avoid HttpMediaTypeNotAcceptableException on standalone tomcat
        configurer.favorPathExtension(false);
      

      }
      }

    调用url: 请求 url : http://127.0.0.1:8080/user/huangyichun_@.com 返回值如下:

    {
    "requestId": "requestId",
    "result": {
    "name": "huangyichun_@"
    }
    }
    可以看出返回格式是正常了,但是发现返回的name和我们请求的name不太一样,这是因为Spring将url中的"."看做了分隔符,因此产生了问题二。

    问题二:如何匹配包含特殊字符的url,例如/email/huang@gmail.com
    解决方法如下:

    package com.example.demo;

    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
    import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

    /**

    • @author huangyichun

    • @date 2018/12/29

    • /
      @Configuration
      public class SpringServiceConfiguration extends WebMvcConfigurationSupport {

      @Override
      public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

        // to  avoid HttpMediaTypeNotAcceptableException on standalone tomcat
        configurer.favorPathExtension(false); 
      

      }

      /**

      • 解决url后缀包含特殊字符
      • @param configurer
      • /
        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.setUseSuffixPatternMatch(false);
        }
        }
        请求上面的url,返回结果如下:

    {
    "requestId": "requestId",
    "result": {
    "name": "huangyichun_@.com"
    }
    }
    问题三:采用注解方式自定义异常以json格式返回的,在包含特殊Url时,无法抛出自己想要的异常格式
        该场景出现的比较特殊,是在Controller方法中,使用RestTemplate调用其他服务,例如查询用户是否存在,结果为不存在,然后该服务抛出了一个not fount 404的json异常信息。项目中采用了注解方法进行异常处理,在返回时,Spring进行序列化后导致结果不是自己想要的格式。

    解决思路:

    让自定义异常处理类继承HandlerExceptionResolver,然后实现默认方法,对于抛出的异常进行最后的转换,结果符合自己需求。下面直接给出参考代码,和上面示例不是同一个项目,仅供参考

    @ControllerAdvice
    public class CustomExceptionHandler extends BaseController implements HandlerExceptionResolver {
    private static Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class);

    private ServiceError serviceError = new ServiceError();
    
    @ExceptionHandler(HttpClientErrorException.class)
    @ResponseBody
    public OpenApiResponse httpClientErrorException(HttpServletRequest request, HttpServletResponse response, HttpClientErrorException ex){
        logger.error("requestId:{}  httpClientErrorException:{}",getRequestId(request),ex);
        OpenApiResponse res = new OpenApiResponse(getRequestId(request));
        String msg = ex.getResponseBodyAsString();
        if(StringUtils.isNotBlank(msg)){
            try{
                JSONObject jsonObject = JSON.parseObject(msg);
                int code = ex.getStatusCode().equals(HttpStatus.OK) ? 402 :  ex.getStatusCode().value();
                String status = jsonObject.getString("code");
                String message = jsonObject.getString("message");
                Map<String, String> detail = JsonUtils.jsonObject2Map(jsonObject.getJSONObject("details"));
                serviceError.setCode(code);
                serviceError.setMessage(StringUtils.isNotBlank(message) ? message : "内部调用错误");
                serviceError.setStatus(StringUtils.isNotBlank(status) ? status : "INVOKE_ERROR");
                if (detail != null) {
                    serviceError.setDetails(ArrayUtils.toArray(detail));
                }
                res.setError(serviceError);
                response.setStatus(code);
                return res;
            }
            catch (Exception e){
                logger.error("解析错误,",e);
            }
        }
        serviceError.setCode(500);
        serviceError.setMessage("内部调用错误");
        serviceError.setStatus("INNER_ERROR");
        response.setStatus(500);
        res.setError(serviceError);
        return res;
    }
    
    @ExceptionHandler
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public OpenApiResponse defaultException(HttpServletRequest request,HttpServletResponse response, Exception e){
        logger.error("requestId:{}  spring捕获运行时异常:{}",getRequestId(request),e);
        OpenApiResponse res = new OpenApiResponse(getRequestId(request));
        ServiceError serviceError = new ServiceError();
        serviceError.setCode(500);
        serviceError.setMessage("内部错误");
        serviceError.setStatus("INNER_ERROR");
        res.setError(serviceError);
        response.setStatus(500);
        return res;
    }
    
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        FastJsonJsonView fastJsonJsonView = new FastJsonJsonView();
        Map<String,Object> map = new HashMap<>();
        Map<String, Object> result = new HashMap<>();
        map.put("requestId", getRequestId(request));
        map.put("result", result);
        map.put("error", serviceError);
        fastJsonJsonView.setAttributesMap(map);
        ModelAndView mv =new ModelAndView();
        mv.setView(fastJsonJsonView);
        return mv;
    }
    

    }
    1人点赞
    Spring boot

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(7条)

报告相同问题?

问题事件

  • 系统已结题 12月25日
  • 已采纳回答 12月17日
  • 修改了问题 12月16日
  • 创建了问题 12月16日

悬赏问题

  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上
  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因