3

记录Ajax请求报415与404问题

 2 years ago
source link: https://segmentfault.com/a/1190000040846702
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

问题描述与分析

今天帮同学旁边同事解决了一个问题,问题是这样的:我们有一个前后端未分离的项目agentBuyFreemark+JQuery),同事想本地启动agentBuy服务(http:localhost:8001),联调后端同事的本地web-inquiry服务(http://127.168.24.68:9366),直接联调会有跨域问题,于是同事本地启动网关服务(spring cloud gateway)将agentBuyweb-inquiry服务代理到http:webagent.java.com:10000进行联调,但是发现接口报了415

// agentBuy  
var params = {
  "storeId":"HL000001",
  "quoteType":"AUTO",
  "enable":"Y"
};
$.ajax({
  url: WEB_ROOT + '/inquiryWeb/supply/quote/enable', // 在本地为http:webagent.java.com:10000/inquiryWeb/supply/quote/enable
  type: 'post',
  data : params,
  dataType: 'json',
  success: function (response) {
    // code...
  }
})

发现请求的入参会转化成键值对的形式,Request Payload

storeId=HL000001&quoteType=AUTO&enable=Y

响应状态码为415(Unsupported Media Type),表示服务器无法处理请求附带的媒体格式 (不支持的媒体类型)

@Log4j2
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SupplyQuotationConfigController {

  private final SupplyQuotationConfigClient supplyQuotationConfigClient;

  private static final String REQUEST_NOT_VALIDATE = "请求参数校验不通过~";
  private static final String INTERNAL_SERVER_ERROR = "网络异常,请稍后重试~";

  @PostMapping("/supply/quote/enable")
  public ResponseEntity<Result<Boolean>> setSupplyQuoteEnable(@RequestBody SupplyQuoteEnableRequest request) {
    if (null == request || !request.validate()){
      return new ResponseEntity<>(new Result<>(HttpStatus.BAD_REQUEST.value(), REQUEST_NOT_VALIDATE, Boolean.FALSE), HttpStatus.OK);
    }
    try {
      supplyQuotationConfigClient.setSupplyQuoteEnable(SupplyQuotationConfigFactory.toSupplyQuotationEnableRequest(request));
      return new ResponseEntity<>(new Result<>(HttpStatus.OK.value(), null, Boolean.TRUE), HttpStatus.OK);
    }catch (HttpMessageException e){
      return new ResponseEntity<>(new Result<>(e.getStatusCode(), e.getMessage(), Boolean.FALSE), HttpStatus.OK);
    }catch (Exception e){
      return new ResponseEntity<>(new Result<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), INTERNAL_SERVER_ERROR, Boolean.FALSE), HttpStatus.OK);
    }
  }
}

在排查后端接口发现,请求参数使用了@RequestBody注解,用来接收前端传递给后端的json字符串数据,而现在传的键值对的类型,因为如果没有自行指定request header Content-Type,默认为application/x-www-form-urlencoded,因此前后端定义的参数类型不一致,从而报了415错误。

request header中设置Content-Type:application/json就可以解决415问题,但是重新请求却报了404,我仔仔细细对照了一遍请求路径,发现并没有什么问题,并且使用postman本地调试接口也没有问题,百思不得其解。

后面发现request header中设置了Content-Type:application/json,但Request Payload还是为键值对:

storeId=HL000001&quoteType=AUTO&enable=Y

难道是因为键值对参数会追加在URL后面使得请求路径不对?这是为何会变成键值对呢?

因为在没有 MIME 类型的情况下,或者在某些浏览器认为设置的MIME 类型不正确情况下,浏览器可能会执行MIME 嗅探,通过查看资源的字节来猜测正确的 MIME 类型。上面我们设置Content-Type:application/jsonapplication/json表示需要传一个json字符串,但是我们传的是json数据,浏览器认为设置的MIME 类型不正确,将参数判定成了键值对形式,因此才导致后续请求报404

我们只需要将入参改成json字符串即可解决该问题:

// agentBuy  
var params = {
  "storeId":"HL000001",
  "quoteType":"AUTO",
  "enable":"Y"
};
$.ajax({
  url: WEB_ROOT + '/inquiryWeb/supply/quote/enable', // 在本地为http:webagent.java.com:10000/inquiryWeb/supply/quote/enable
  type: 'post',
  data : JSON.stringify(params), // 改成json字符串
  dataType: 'json',
  success: function (response) {
    // code...
  }
})

ajax post请求报错415或400解决方案

MIME 嗅探

https://developer.mozilla.org...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK