加關(guān)鍵詞的網(wǎng)站石家莊網(wǎng)站seo外包
#1 問題描述
在基于Spring Boot
的項目中實現(xiàn)了請求轉(zhuǎn)發(fā)(使用 RestTemplate 的 exchange 方法)的功能,忽然在前端報net::ERR_CONTENT_DECODING_FAILED 200 (OK)
的錯誤,后端及上游系統(tǒng)日志均顯示請求已完成。
#2 原因探尋
上述錯誤字面意思為內(nèi)容解碼失敗
,就是說瀏覽器拿到后端數(shù)據(jù)后沒辦法正常解碼。此時我們看看請求響應(yīng)的編碼
可以看到上游系統(tǒng)啟用了響應(yīng)壓縮
,然后中轉(zhuǎn)系統(tǒng)讀取方式為:
restTemplate.exchange(entity, String::class.java)
故當(dāng)上游系統(tǒng)的響應(yīng)啟用壓縮后,中轉(zhuǎn)系統(tǒng)按String
讀取再返回給前端,瀏覽器拿到數(shù)據(jù)后通過響應(yīng)頭識別到是gzip
編碼則嘗試解壓,導(dǎo)致前面出現(xiàn)的異常。
#3 修復(fù)
要修復(fù)其實也很簡單,在中轉(zhuǎn)系統(tǒng)中用字節(jié)數(shù)組
格式讀取響應(yīng)即可(兼容上游系統(tǒng)的各種格式的響應(yīng)),完整代碼如下:
class ServiceRoute {val logger = LoggerFactory.getLogger(javaClass)val restTemplate = RestTemplate().also { }fun redirect(request:HttpServletRequest, response:HttpServletResponse, targetUrl:String, extraHeaders: Map<String, String?>?=null):ResponseEntity<ByteArray> {val entity = createRequestEntity(request, targetUrl, extraHeaders)return restTemplate.exchange(entity, ByteArray::class.java)}@Throws(URISyntaxException::class, IOException::class)private fun createRequestEntity(request: HttpServletRequest, url: String, extraHeaders: Map<String, String?>?): RequestEntity<*> {val httpMethod = HttpMethod.valueOf(request.method)val headers = parseRequestHeader(request)extraHeaders?.forEach { (k, v) -> headers.add(k, v) }//將原始請求轉(zhuǎn)換為字節(jié)數(shù)組val body = StreamUtils.copyToByteArray(request.inputStream)return RequestEntity<Any>(body, headers, httpMethod, URI(url))}/*** 復(fù)制原始請求的 header 信息*/private fun parseRequestHeader(request: HttpServletRequest): MultiValueMap<String, String?> {val headers = HttpHeaders()val headerNames: List<String> = Collections.list(request.headerNames)for (headerName in headerNames) {val headerValues: List<String> = Collections.list(request.getHeaders(headerName))for (headerValue in headerValues) {headers.add(headerName, headerValue)}}return headers}
}
使用示例
@RequestMapping("route/**", name = "轉(zhuǎn)發(fā)請求")
fun redirect(response:HttpServletResponse):ResponseEntity<*> {val path = request.servletPath.replace("/route/", "")return try{//自定義請求頭val extraHeaders = mapof("from" to "中介系統(tǒng)")route.redirect( request, response, "http://localhost:8080/${path}", extraHeaders ).also {//此處可查看返回內(nèi)容}}catch (e:Exception) {logger.error("[SERVICE-ROUTE] 轉(zhuǎn)發(fā)失敗", e)ResponseEntity(e.message, HttpStatus.INTERNAL_SERVER_ERROR)}finally {//此處可以做一些后續(xù)操作}
}