問題描述與分析
今天幫同學旁邊同事解決了一個問題,問題是這樣的:我們有一個前後端未分離的專案agentBuy
(Freemark+JQuery
),同事想本地啟動agentBuy
服務(http:localhost:8001
),聯調後端同事的本地web-inquiry
服務(http://127.168.24.68:9366
),直接聯調會有跨域問題,於是同事本地啟動閘道器服務(spring cloud gateway
)將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...
}
})
參考: