問題描述與分析
今天幫同學旁邊同事解決了一個問題,問題是這樣的:我們有一個前後端未分離的項目agentBuy(Freemark+JQuery),同事想本地啓動agentBuy MVC服務(http:localhost:8001),聯調後端同事的本地啓動的web-inquiry服務(http://127.168.24.68:9366),直接聯調會有跨域問題,於是同事本地啓動網關服務webagent將agentBuy、web-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"eType=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"eType=AUTO&enable=Y
難道是因為鍵值對參數會追加在URL後面使得請求路徑不對?這是為何會變成鍵值對呢?
因為在沒有 MIME 類型的情況下,或者在某些瀏覽器認為設置的MIME 類型不正確情況下,瀏覽器可能會執行MIME 嗅探,通過查看資源的字節來猜測正確的 MIME 類型。上面我們設置Content-Type:application/json,application/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...