请求url写的没错,但还是报404错误

我们常见404是请求的url写错了,导致找不到请求路径,所以报404,但是还有一种情况会报404,你知道嘛?

1. 问题描述

客户端请求的url没有问题,后台接口也成功调用,并且后台接口没有任何报错信息。客户端浏览器chrome中可见404错误。在Preview中,可发现请求url不是原本我请求的url。

2. 看代码,引出问题

@Controller
@RequestMapping(value = "/cms/v1/module/business_script")
public class BusinessScriptController {

  @RequestMapping(value = "/{code}/runWithDownload", method = RequestMethod.POST)
  public void runWithDownload(@PathVariable String code,
                              @RequestBody(required = false) Map args) {
     ServletRequestAttributes attrs = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
     HttpServletResponse response = attrs.getResponse();
    // 该接口为下载接口, 此处省略一万行代码
  }
}

当我客户端访问 /cms/v1/module/business_script/test/runWithDownload 的时候,发现该接口已经成功调用,并且没有报任何错误,但是从浏览器中可以看到接口已经报404错误:

Headers信息

Preview信息

Response信息

3. 解决方案

  • 方案一
    接口方法上加上 @ResponseBody
@Controller
@RequestMapping(value = "/cms/v1/module/business_script")
public class BusinessScriptController {

  @ResponseBody
  @RequestMapping(value = "/{code}/runWithDownload", method = RequestMethod.POST)
  public void runWithDownload(@PathVariable String code,
                              @RequestBody(required = false) Map args) {
     ServletRequestAttributes attrs = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
     HttpServletResponse response = attrs.getResponse();
    // 该接口为下载接口, 此处省略一万行代码
  }
}

@ResponseBody是方法级的注解

  • 方案二
    将 @Controller 改为 @RestController
@RestController
@RequestMapping(value = "/cms/v1/module/business_script")
public class BusinessScriptController {

  @RequestMapping(value = "/{code}/runWithDownload", method = RequestMethod.POST)
  public void runWithDownload(@PathVariable String code,
                              @RequestBody(required = false) Map args) {
     ServletRequestAttributes attrs = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
     HttpServletResponse response = attrs.getResponse();
    // 该接口为下载接口, 此处省略一万行代码
  }
}

@RestController 相当于@Controller + @ResponseBody

  • 方案三
    在接收参数里加上 HttpServletResponse response
@Controller
@RequestMapping(value = "/cms/v1/module/business_script")
public class BusinessScriptController {

  @RequestMapping(value = "/{code}/runWithDownload", method = RequestMethod.POST)
  public void runWithDownload(HttpServletResponse response,
                              @PathVariable String code,
                              @RequestBody(required = false) Map args) {
     ServletRequestAttributes attrs = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
     HttpServletResponse response = attrs.getResponse();
    // 该接口为下载接口, 此处省略一万行代码
  }
}

Spring对HttpServletResponse进行了包装,所以只要在接收参数里加上HttpServletResponse,再通过RequestContextHolder的方式获取到的HttpServletResponse也是包装后的对象。

4. 扩展

4.1 程序里如何获取和HttpServletRequest和HttpServletResponse
  • 通过接收参数方式
@RequestMapping(value = "/{code}/runWithDownload", method = RequestMethod.POST)
public void runWithDownload(HttpServletRequest request, HttpServletResponse response) {
     
}
  • 通过注解方式
@Autowired  
private  HttpServletRequest request; 

@Autowired  
private  HttpServletResponse response;  
  • 上下文获取
    在web.xml配置监听器
<listener>
      <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

程序中使用

ServletRequestAttributes attrs = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attrs.getRequest();
HttpServletResponse response = attrs.getResponse();
4.2 @RequestBody和@ ResponseBody解释的区别?

使用 @RequestMapping后,springmvc默认的是jsp那种解析视图的方式,返回值通常解析为跳转路径。
@ResponseBody是作用在方法上的,表示该方法的返回结果直接写入 HTTP response body 中,而不适用默认的视图解析方式。
@RequestBody是作用在形参列表上,用于将前台发送过来固定格式的数据【xml 格式或者 json等】封装为对应的 JavaBean 对象,封装时使用到的一个对象是系统默认配置的 HttpMessageConverter进行解析,然后封装到形参上。

4.3 # @Controller和@RestController的区别?

@RestController注解相当于@ResponseBody + @Controller合在一起的作用。

  • 如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,或者html,配置的视图解析器 InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。

  • 如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。

5. 友情链接

Spring框架:@RestController与@Controller

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值