リクエスト入力ストリームから入力を読み取り、JacksonMapperを使用してPOJOに変換するこのコードがあります。 guiceサポート付きの桟橋7コンテナで実行されます。
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
RequestType requestType = mapper.readValue(req.getInputStream(), RequestType.class);
} Catch(Exception ex) {
....
}
}
ただし、負荷がかかると、次の例外がスローされることがあります。クライアントを確認しましたが、有効なjson文字列を送信していると確信しています。何が問題なのですか?負荷がかかった状態でのJetty7の予想される動作ですか?
Java.io.EOFException: No content to map to Object due to end of input
at org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.Java:2433)
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.Java:2385)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.Java:1637)
at com.ea.wsop.user.LoginServlet.processRequest(LoginServlet.Java:69)
at com.ea.wsop.user.LoginServlet.doPost(LoginServlet.Java:63)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$doPost$0(<generated>)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.Java:228)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.Java:72)
at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.Java:130)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.Java:72)
at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.Java:52)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.doPost(<generated>)
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:727)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$8(<generated>)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.Java:228)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.Java:72)
at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.Java:130)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.Java:72)
at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.Java:52)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.service(<generated>)
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:820)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$9(<generated>)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.Java:228)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.Java:72)
at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.Java:130)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.Java:72)
at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.Java:52)
at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.service(<generated>)
at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.Java:263)
事前に消費されている場合は空になります。これは、HttpServletRequest
でgetParameter()
、getParameterValues()
、getParameterMap()
、getReader()
などを呼び出すたびに暗黙的に実行されます。 getInputStream()
を呼び出す前に、それ自体でリクエスト本文から情報を収集する必要がある種類のメソッドを呼び出さないようにしてください。サーブレットがそれを行っていない場合は、同じURLパターンにマップされているサーブレットフィルターのチェックを開始します。
更新:これはGAE1.5固有のようです。も参照してください
彼らがそれを修正するまで、私は解決策/回避策がないのではないかと心配しています。 tryを使用して、Filter
内で使用できるかどうかを確認し、使用できる場合は、コピーしてリクエスト属性として保存できます。ただし、これはmight一部のGAEサーブレットによる以降の処理に影響します。
SpringBootアプリケーションの実行でも同様の問題が発生しました。私のSpringBootアプリは、リクエスト本文を読み取って処理する単純なDispatcher
サーブレットです。
私の場合、curlコマンドラインが_-d {some-data}
_を使用し、特定のコンテンツタイプを設定しない場合、クライアント(curl
)はapplication/x-www-form-urlencodedのコンテンツタイプヘッダーを設定します_-Hcontent-type=some-other-media-type
_経由のヘッダー。
SpringBootが実行するApacheCatalinaサーブレットエンジン内で、Request
クラスはparseParameters()
で次のテストを行います。
_ if (!("application/x-www-form-urlencoded".equals(contentType))) {
success = true;
return;
}
_
他の_content-type
_値の場合、Request
はここに戻ります。
ただし、コンテンツタイプが_application/x-www-form-urlencoded
_と一致する場合、Request
は続行します。
_ try {
if (readPostBody(formData, len) != len) {
parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE);
return;
}
} catch (....)
_
これは本体を消費します。したがって、私の場合、myサーブレットは、request.getInputStream()
を呼び出して、からread()
を試行する以外に何もしません。それは、すでに手遅れです-ランタイムRequest
はすでに入力を読み取り、バッファリングまたは読み取り解除しません。唯一の回避策は、別の_Content-Type
_を設定することです。
犯人はOrderedHiddenHttpMethodFilter(HiddenHttpMethodFilter).doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain)
行70です
_"_method"
_クエリパラメータを探しています。
追加することでフィルターを無効にすることができました
_@Bean
public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
_
(これは解決に使用されました 別の問題 )
Jetty 6.1.15ではリクエストInputStreamが常に空であるという問題があり、「Content-Type」ヘッダーがないか間違っていることが原因であることがわかりました。
HttpUrlConnectionを使用して別のJavaプログラムでリクエストを生成します。Content-Typeヘッダーを明示的に設定しなかった場合、request.getInputStream()
によって返されるInputStream
は受信プログラムは常に空でした。コンテンツタイプを「binary/octet-stream」に設定すると、リクエストのInputStream
に正しいデータが含まれていました。
getInputStream()
の前にリクエストオブジェクトで呼び出される唯一のメソッドはgetContentLength()
です。
投稿でこの問題が発生しました。パラメータを読み取る前に、まず入力ストリームを読み取り、キャッシュに入れることで解決しました。それはトリックをするようでした
Spring Boot2.2.1プロジェクトでorg.springframework
のデバッグログを有効にして、spring-webmvc 5.2.1を使用すると、問題が発生しました。
これは、Content-Type
がapplication/x-www-form-urlencoded
の場合に入力ストリームを読み取るパラメータマップのリクエストロギングが原因で発生します。 この春号 はそれに関連していると思います。
問題の原因となる次のコードを参照してください。
private void logRequest(HttpServletRequest request) {
LogFormatUtils.traceDebug(logger, traceOn -> {
String params;
if (isEnableLoggingRequestDetails()) {
params = request.getParameterMap().entrySet().stream()
.map(entry -> entry.getKey() + ":" + Arrays.toString(entry.getValue()))
.collect(Collectors.joining(", "));
}
else {
params = (request.getParameterMap().isEmpty() ? "" : "masked");
}
...
私は結局 問題 を報告し、代わりにリクエストのコンテンツタイプを変更しました。
体系的なアプローチは次のとおりです。
HttpServletRequest->getInputStream()
が呼び出される前のコードにブレークポイントを作成します。HttpServletRequest->getInputStream()
メソッドにステップインすると、... Implクラスになります。getInputStream()
実装、またはそのread()
メソッドに新しいブレークポイントを設定します。この問題の原因となるバグがあったmod_jk1.2.39を使用していました。 1.2.40にアップデートした後、動作を開始しました。