openFeign服務之間調(diào)用保持請求頭信息處理方式
openFeign服務間調(diào)用保持請求頭信息處理
1、注意特殊情況,在定時任務或者內(nèi)部之間調(diào)用,沒有request的時候,不要處理直接返回。
2、在GET請求,參數(shù)確放在Body里面?zhèn)鬟f的情況,restTemplate是不認識的,所以這里要轉(zhuǎn)化下處理,然后清空body數(shù)據(jù)
3、在請求過程中如果出現(xiàn)java.io.IOException: too many bytes written異常,請參考保持請求頭造成請求頭和content-length不一致
/** * 解決服務調(diào)用丟失請求頭的問題 * @author 大仙 * */ @Component public class FeignConfiguration implements RequestInterceptor{ private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private ObjectMapper objectMapper; @Override public void apply(RequestTemplate template) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder .getRequestAttributes(); // 注意: RequestContextHolder依賴于 ThreadLocal, 所以在hystrix的隔離策略為THREAD、MQ的消費者、定時任務調(diào)用feignClient時,此處應為null if (attributes == null) { return; } HttpServletRequest request = attributes.getRequest(); Enumeration<String> headerNames = request.getHeaderNames(); if (headerNames != null) { while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String values = request.getHeader(name); template.header(name, values); } } logger.info("保持請求頭"); //feign 不支持 GET 方法傳 POJO, json body轉(zhuǎn)query if (template.method().equals("GET") && template.requestBody().asBytes() != null) { try { JsonNode jsonNode = objectMapper.readTree(template.requestBody().asBytes()); Request.Body.empty(); Map<String, Collection<String>> queries = new HashMap<>(); buildQuery(jsonNode, "", queries); template.queries(queries); } catch (IOException e) { //提示:根據(jù)實踐項目情況處理此處異常,這里不做擴展。 e.printStackTrace(); } } } /** * 改造 * @param jsonNode * @param path * @param queries */ private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) { // 葉子節(jié)點 if (!jsonNode.isContainerNode()) { if (jsonNode.isNull()) { return; } Collection<String> values = queries.get(path); if (null == values) { values = new ArrayList<>(); queries.put(path, values); } values.add(jsonNode.asText()); return; } // 數(shù)組節(jié)點 if (jsonNode.isArray()) { Iterator<JsonNode> it = jsonNode.elements(); while (it.hasNext()) { buildQuery(it.next(), path, queries); } } else { Iterator<Map.Entry<String, JsonNode>> it; it = jsonNode.fields(); while (it.hasNext()) { Map.Entry<String, JsonNode> entry = it.next(); if (StringUtils.hasText(path)) { buildQuery(entry.getValue(), path + "." + entry.getKey(), queries); } else { // 根節(jié)點 buildQuery(entry.getValue(), entry.getKey(), queries); } } } } }
保持請求頭造成請求頭和content-length不一致
Request processin g failed; nested exception is feign.RetryableException: too many bytes written
2020-09-08 14:07:14.718 ERROR 16146 --- [io-12000-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processin g failed; nested exception is feign.RetryableException: too many bytes written executing POST http://pay/wx/create] with root cause java.io.IOException: too many bytes written at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(HttpURLConnection.java:3574) ~[na:1.8.0_212] at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(HttpURLConnection.java:3565) ~[na:1.8.0_212] at feign.Client$Default.convertAndSend(Client.java:181) ~[feign-core-10.4.0.jar!/:na] at feign.Client$Default.execute(Client.java:77) ~[feign-core-10.4.0.jar!/:na] at org.springframework.cloud.openfeign.ribbon.RetryableFeignLoadBalancer$1.doWithRetry(RetryableFeignLoadBalancer.java:114) ~[spring-cloud-openfeign-core-2.1.5.RELEASE.jar!/:2.1.5.RELEASE] at org.springframework.cloud.openfeign.ribbon.RetryableFeignLoadBalancer$1.doWithRetry(RetryableFeignLoadBalancer.java:94) ~[spring-cloud-openfeign-core-2.1.5.RELEASE.jar!/:2.1.5.RELEASE] at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:287) ~[spring-retry-1.2.5.RELEASE.jar!/:na] at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:180) ~[spring-retry-1.2.5.RELEASE.jar!/:na] at org.springframework.cloud.openfeign.ribbon.RetryableFeignLoadBalancer.execute(RetryableFeignLoadBalancer.java:94) ~[spring-cloud-openfeign-core-2.1.5.RELEASE.jar!/:2.1.5.RELEASE] at org.springframework.cloud.openfeign.ribbon.RetryableFeignLoadBalancer.execute(RetryableFeignLoadBalancer.java:54) ~[spring-cloud-openfeign-core-2.1.5.RELEASE.jar!/:2.1.5.RELEASE] at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:104) ~[ribbon-loadbalancer-2.3.0.jar!/:2.3.0] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) ~[ribbon-loadbalancer-2.3.0.jar!/:2.3.0] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) ~[ribbon-loadbalancer-2.3.0.jar!/:2.3.0] at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:231) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:228) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.Observable.unsafeSubscribe(Observable.java:10327) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144) ~[rxjava-1.3.8.jar!/:1.3.8] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:185) ~[ribbon-loadbalancer-2.3.0.jar!/:2.3.0] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.3.0.jar!/:2.3.0] at rx.Observable.unsafeSubscribe(Observable.java:10327) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.Observable.unsafeSubscribe(Observable.java:10327) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.Subscriber.setProducer(Subscriber.java:209) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.3.8.jar!/:1.3.8] at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.3.8.jar!/:1.3.8
原因是:body是跟Content-Length 有關(guān)系
復制的時候是所有頭都復制的,可能導致Content-length長度跟body不一致. 所以只需要判斷如果是Content-length就跳過
解決方式:更改復制邏輯
while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); // 跳過 content-length if (name.equals("content-length")){ continue; } String values = request.getHeader(name); template.header(name, values); }
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)之二叉搜索樹詳解
二叉搜索樹作為一個經(jīng)典的數(shù)據(jù)結(jié)構(gòu),具有鏈表的快速插入與刪除的特點,同時查詢效率也很優(yōu)秀,所以應用十分廣泛。本文將詳細講講二叉搜索樹的原理與實現(xiàn),需要的可以參考一下2022-06-06mybatis-plus saveOrUpdateBatch踩坑記錄
這篇文章主要介紹了mybatis-plus saveOrUpdateBatch踩坑記錄,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12