結論:
装うが、あなたは、ApacheのHttpClientを使用している場合は、PUT / POST、とき質量参加RequestBodyを使用するようにしてください。
そうでない場合はRequestBody、のQueryStringのApacheのHttpClientデータが少ない界面側よりもかかりますのでことを、キー値を提出する形式に変換されます
与えられている
サービスAへのインタフェース定義コピーサービスBいつものようにセルフテストに次いでFeignClientポストマン [エラートーンサービスAがサービスB]の間のインターフェイスエラー。
エラーメッセージ:
通常の状況下ではそこに起こることができないため、メッセージは、Wuguai非常にエレガントではありません。つまり、攻撃者は、このプロンプトストップパラメータは非常に厳格なチェックが表示されます。
データの生産と消費の
Bが提供するサービスのサービス[生産]:
サービスのフロントエンドに提供されるサービス:
サービスコンシューマは、サービス[B]を呼び出します。
これが書かれた当時は怠け者盗む:のQueryStringの直接の使用を、DTOデータ伝送の新たな定義を必要としません。エラー彼らは異常な方法を取らないので、これはアナリスト以下のもの、です。
BugShooting:ログの分析
要求されたデータストリームによって、ログ順序:サービスログ[A]は期待値と一致しています。
サービスB [予想にログ矛盾:以下のQueryString]:
問題が配置されています:サービスコールサービスB、失われたQueryString引数
印刷ログの重要性を!印刷ログは便利な学習です
そして、チェックコード、それに何も間違っては、特別のQueryStringマーク@RequestParamもマークされました!奇妙
BugShooting:巨人の肩の上に立ちます
私はピットを通じて誰かのワタリは、Baiduは、googleのかどうかを確認したい、ビングは、関連するケースの情報を見つけることができませんでした。介してのみ参照@Headers ("ファイルアプリケーション/ JSONのContent-Type" )または@PutMapping (値= "/提供/ sync_strategies / syncStrategyId {}" 、ヘッダ= { "タイプ内容:ファイルアプリケーション/ JSON" })に明示的に宣言要求ヘッダーのアプローチ、次の無用を試してみてください。
BugShooting:デバッグ[ ニルヴァーナ]
我々は、この使用していないだろう、すべてのパラメータによって直接、事実を装うソースを再ソートする必要があり、再び:@RequestBodyを解決しますが、旗の前に立って自分自身を与えることができます。
デバッグ、それが発見され、このような論理PUTやPOSTメソッドがある場合にはApacheのHttpClient:
そこのQueryStringなくrequestBodyは、のQueryStringは、URLに置かれますが、QueryStringには、キー値データ形式の構造、形状やマスコミに変換されません提出:
org.apache.http.client.methods.RequestBuilder#ビルドは、
指定したアプリケーション/ X-WWW-フォーム- URLエンコードを、 とにRequestBodyのQueryStringを書き込みます。
org.apache.http.client.entity.UrlEncodedFormEntity#UrlEncodedFormEntity(java.lang.Iterable <?org.apache.http.NameValuePairが伸びる>、いるjava.nio.charset.Charset)
org.apache.http.client.utils.URLEncodedUtils#フォーマット(java.lang.Iterable <?延び org.apache.http.NameValuePair>は、チャー、いるjava.nio.charset.Charset)は、実際に、フォームへのQueryStringを変換しますフォームを送信するだけでなく、HTPP契約に沿ったものではなく、あなたができるこの方法を受信するための受信者が必要です。サービスBの使用、上のスクリーンショットを参照してください。そして、もちろん、我々は立ち上がっていなかった、のQueryStringからすなわち値に、@RequestParamを。簡単に言えば、ちょうど同じ宅配便を取ります。南門は、通常は取られますが、宅配便は北ゲートに行けば、あなたにこの変更を指示する必要がありません。南ゲートにも、あなたがた場合は、手の届かないところに間違いです。
2つの異なるデータ伝送
エラーはApacheのHttpClientは、要求を開始する場合:
所望の方法:
問題を発見し、解決策が明確になる:それはできませんRequestBodyを追加し
、私は冗長RequestBodyの行くを送っていること:
我々はすでにReqestBodyの値を見ることができます
QueryStringは、処理ロジックが変更するかどうかを見ていき、あなたが希望別のを見ることができます:
しかし、このアプローチは、これは無効なパラメータを削除しますように、他の学生は、コードを見ながら、そのサービスが利用できない、コードの増加のメンテナンスコスト、パラメータを必要としない業務が増加します。
したがって、要求はDTOパラメータにパッケージされ、その後、データは、体内で渡すことができます。
サプリメント
1は、ApacheのHTTPクライアントエンティティの初期化コードの入力] [RequestBody:
feign.httpclient.ApacheHttpClient#toHttpUriRequest
2、条件ピット上のステップ:装う使用するクライアントのApache Httpクライアントとして指定してください
< 依存> < groupIdを> org.springframework.cloud </ groupIdを> < たartifactId >春・クラウド・スタータopenfeign </ たartifactId > </ 依存関係> <! - https://mvnrepository.com/artifact/io.github .openfeign /装う-のHTTPClient - > < 依存> < groupIdを> io.github.openfeign </ groupIdを> < たartifactId >装う-のHTTPClient </ たartifactId > <バージョン> 10.8 </ バージョン> </ 依存関係>
この依存関係の装う - HTTPClientの以前のバージョンでは、以下を追加する必要があります。
< 依存性> < のgroupId > org.apache.httpcomponents </ のgroupId > < たartifactId > HTTPClientの</ たartifactId > </ 依存>
説明:サービスがチューン権を呼び出しの間にApacheのHttpClientはベテランのHTTPクライアントでは、接続プールのタイムアウト時間を設定することができます。この代替をサポートするために、最初から春クラウドBrixtion.SR5バージョン。
古典的なHttpClientを設定:
// のHttpClient 4.5.2古典的な接続プールの構成用い プライベートCloseableHttpClient getHttpClientを(){ // ソケット工場関連するアクセス・プロトコル登録 レジストリ<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder。<ConnectionSocketFactory> 作成() .register( "HTTP" 、PlainConnectionSocketFactory。 INSTANCE) .register( "HTTPS" 、SSLConnectionSocketFactory.getSocketFactory()) .build(); // HttpConnectionFactory:設定書込み要求/応答処理構文解析 HttpConnectionFactory <HttpRoute、ManagedHttpClientConnection>はconnectionFactory = 新しい新しい ManagedHttpClientConnectionFactoryを( DefaultHttpRequestWriterFactory.INSTANCE、 DefaultHttpResponseParserFactory.INSTANCE ); // DNSリゾルバ DNSResolver DNSResolver = SystemDefaultDnsResolver.INSTANCE; // 接続プール管理プログラム作成 PoolingHttpClientConnectionManagerマネージャー= 新新PoolingHttpClientConnectionManager(socketFactoryRegistry、はconnectionFactory、DNSResolverを); // 設定されたデフォルトパラメータソケット manager.setDefaultSocketConfig(SocketConfig。カスタム()setTcpNoDelay(真の).build()); manager.setMaxTotal( 300); // 接続の最大数を設定します。この値は、新しい接続要求の上には、待って、ブロックする必要がある // ルーティングがMaxTotalの内訳です。 //各経路の接続の実際の最大数は、デフォルト値DefaultMaxPerRouteによって制御されます。 // MaxPerRouteは、大規模な同時実行をサポートするには小さすぎる設定:ConnectionPoolTimeoutException:プールから接続タイムアウトを待っ manager.setDefaultMaxPerRoute(200); // ルートごとの最大接続数 manager.setValidateAfterInactivity(* 1000年5); // 接続から長い、デフォルト2S後に非アクティブに一度認証するために、接続プール、接続のニーズを取得する際 // 設定されるデフォルトのリクエストパラメータ RequestConfig defaultRequestConfig = RequestConfig.custom() .setConnectTimeout( * 1000 2)// 2Sへの接続タイムアウト 。 setSocketTimeout(* 1000年。5)// タイムアウト5Sへのデータ待ち .setConnectionRequestTimeout(2 * 1000)//タイムアウトが2Sに設定されている待機中の接続プールから接続の取得 // .setProxy(新しい新しいプロキシ(Proxy.Type.HTTP、たInetSocketAddress新新(「192.168.0.2」、1234)))// プロキシアップセット .buildを(); CloseableHttpClient closeableHttpClient = HttpClients.custom() .setConnectionManager(マネージャ) (.setConnectionManagerShared falseに)// 接続プールモードが共有されていない、これは共有が他のHttpClientと共有されているかどうかを指す .evictIdleConnections(60、TimeUnit.SECONDS)//は定期的にアイドル接続回収 .evictExpiredConnectionsを()// 回復が接続期限切れ .setConnectionTimeToLive(60、TimeUnit.SECONDS)//長い接続情報の決定に基づいて、設定されていない場合、生存期間を接続し .setDefaultRequestConfig(defaultRequestConfig)// デフォルトのリクエストパラメータ設定 .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)// 接続の再利用戦略を、すなわちかどうかキープアライブ .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)// 長い接続構成、すなわち、どのくらい生産取得長い接続 .setRetryHandler(新新 DefaultHttpRequestRetryHandler(0、falseに))// 再試行回数を設定、デフォルトは3回であり、現在は無効オフである .build(); / ** *停止または解放接続プール閉じるために接続され、JVMを再起動 * /スレッド(){ Runtime.getRuntime()addShutdownHook(。新しい @Override 公共 のボイドの実行(){ 試み{ closeableHttpClient.close(); log.info( "HTTPクライアントは、閉じました" ); } キャッチ(IOExceptionを電子){ log.error(e.getMessage()、E)。 } } })。 返すcloseableHttpClientを。 }
https://github.com/helloworldtang/spring-boot-cookbook/blob/master/learning-demo/src/main/java/com/tangcheng/learning/web/config/RestTemplateConfig.java
https://mp.weixin.qq.com/s/N4zqSfMAgB6b5jnUsa1z2w