記錄Ajax請求報415與404問題

記得要微笑發表於2021-10-26

問題描述與分析

今天幫同學旁邊同事解決了一個問題,問題是這樣的:我們有一個前後端未分離的專案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...

相關文章