在很多请求中的 1 个中,我得到响应状态 HTTP 502 Bad Gateway

In 1 of a lot of requests I get response status HTTP 502 Bad Gateway

我写了简单的 class ProxyServlet extends org.eclipse.jetty.proxy.ProxyServlet.Transparent 并与 org.eclipse.jetty.server.Server.

一起使用

当我单调地发送相同的请求时,有时会出错。

我尝试了 jetty 版本:9.4.3.v20170317 和 9.3.15.v20161220。

请求成功的日志为:

2017-03-29 16:11:01 [qtp922145372-30] DEBUG 65e620b0:71 - 886655093 rewriting: http://localhost:8282/api/state-get?hash=1490793061907 -> http://localhost:8888/api/state-get?hash=1490793061907
2017-03-29 16:11:01 [qtp922145372-30] DEBUG 65e620b0:539 - 886655093 proxying to upstream:
GET /api/state-get?hash=1490793061907 HTTP/1.1
Cookie: JSESSIONID=node01lgbitpmvb4lg19wqy2t1vbhhj0.node0
Cache-Control: no-cache
Accept: application/json, text/plain, /
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36
Referer: http://localhost:8282/
Host: localhost:8282
Pragma: no-cache
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8,ru;q=0.6
auth-user: aW50XGFkbWlu
auth-roles: 0JDQtNC80LjQvdC40YHRgtGA0LDRgtC+0YA=

HttpRequest[GET /api/state-get HTTP/1.1]@f5d34a2

2017-03-29 16:11:01 [ProxyServlet-65e620b0-37] DEBUG 65e620b0:599 - 886655093 proxying to downstream:
HttpResponse[HTTP/1.1 200 OK]@66b83d74
Date: Wed, 29 Mar 2017 13:11:01 GMT
Content-Type: application/json;charset=UTF-8
Content-Length: 67
Server: Jetty(9.4.3.v20170317)

2017-03-29 16:11:01 [ProxyServlet-65e620b0-37] DEBUG 65e620b0:138 - 886655093 proxying content to downstream: 67 bytes
2017-03-29 16:11:01 [ProxyServlet-65e620b0-37] DEBUG 65e620b0:618 - 886655093 proxying successful
2017-03-29 16:11:01 [ProxyServlet-65e620b0-37] DEBUG 65e620b0:240 - 886655093 proxying complete

错误请求日志为:

2017-03-29 16:10:31 [qtp922145372-30] DEBUG 65e620b0:71 - 424608794 rewriting: http://localhost:8282/api/state-get?hash=1490793031907 -> http://localhost:8888/api/state-get?hash=1490793031907
2017-03-29 16:10:31 [qtp922145372-30] DEBUG 65e620b0:539 - 424608794 proxying to upstream:
GET /api/state-get?hash=1490793031907 HTTP/1.1
Cookie: JSESSIONID=node01lgbitpmvb4lg19wqy2t1vbhhj0.node0
Cache-Control: no-cache
Accept: application/json, text/plain, /
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36
Referer: http://localhost:8282/
Host: localhost:8282
Pragma: no-cache
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8,ru;q=0.6
auth-user: aW50XGFkbWlu
auth-roles: 0JDQtNC80LjQvdC40YHRgtGA0LDRgtC+0YA=

HttpRequest[GET /api/state-get HTTP/1.1]@34e1eb9e

2017-03-29 16:10:31 [ProxyServlet-65e620b0-38] DEBUG 65e620b0:627 - 424608794 proxying failed
java.io.EOFException: HttpConnectionOverHTTP@6e5c3dff(l:/127.0.0.1:47382 <-> r:localhost/127.0.0.1:8888,closed=false)=>HttpChannelOverHTTP@b1621c8(exchange=HttpExchange@4556a5a3 req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@1f66c7cc(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@3c63c99c{s=START}],recv=HttpReceiverOverHTTP@641b7b9(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]<-SocketChannelEndPoint@764a716f{localhost/127.0.0.1:8888<->/127.0.0.1:47382,ISHUT,fill=-,flush=-,to=5/30000}{io=0/0,kio=0,kro=1}->HttpConnectionOverHTTP@6e5c3dff(l:/127.0.0.1:47382 <-> r:localhost/127.0.0.1:8888,closed=false)=>HttpChannelOverHTTP@b1621c8(exchange=HttpExchange@4556a5a3 req=TERMINATED/null@null res=PENDING/null@null)[send=HttpSenderOverHTTP@1f66c7cc(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator@3c63c99c{s=START}],recv=HttpReceiverOverHTTP@641b7b9(rsp=IDLE,failure=null)[HttpParser{s=CLOSED,0 of -1}]]
 at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.earlyEOF(HttpReceiverOverHTTP.java:310) [jetty-client-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1418) [jetty-http-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.shutdown(HttpReceiverOverHTTP.java:196) [jetty-client-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:143) [jetty-client-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:70) [jetty-client-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:130) [jetty-client-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:116) [jetty-client-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279) [jetty-io-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110) [jetty-io-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.io.ChannelEndPoint.run(ChannelEndPoint.java:124) [jetty-io-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:122) [jetty-util-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.util.thread.strategy.ExecutingExecutionStrategy.invoke(ExecutingExecutionStrategy.java:58) [jetty-util-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:201) [jetty-util-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:133) [jetty-util-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672) [jetty-util-9.4.3.v20170317.jar:9.4.3.v20170317]
 at org.eclipse.jetty.util.thread.QueuedThreadPool.run(QueuedThreadPool.java:590) [jetty-util-9.4.3.v20170317.jar:9.4.3.v20170317]
 at java.lang.Thread.run(Thread.java:745) [?:1.8.0_121]
2017-03-29 16:10:31 [ProxyServlet-65e620b0-38] DEBUG 65e620b0:240 - 424608794 proxying complete

更新:

不知道为什么,有时代理服务器和目标服务器之间的连接会关闭。请求事件未在服务器上实现 servlet。 这是服务器的代码:

            server = new Server(port);

            final String webDir = isNotBlank(webappPath) ? webappPath : new ClassPathResource(WEBAPP_DIR_NAME).getURI().toString();
            final WebAppContext webAppContext = new WebAppContext(webDir, "/" + context);

            webAppContext.setInitParameter("org.eclipse.jetty.servlet.Default.gzip", "true");
            webAppContext.setInitParameter("org.eclipse.jetty.servlet.Default.cacheControl", "max-age=3600,public");

            final ServletHolder apiServletHolder = new ServletHolder(new ApiServlet(getPluginResponseListener(), getPluginListener(), getPluginInfoRequestListener()));
            final String apiServletMapping = "/" + ApiServlet.SERVLET_PATH + "/*";

            webAppContext.addServlet(apiServletHolder, apiServletMapping);
            webAppContext.setMaxFormContentSize(10 * 1024 * 1024);
            webAppContext.setErrorHandler(getErrorHandler());

            server.setHandler(webAppContext);

            server.start();

Wireshark 信息:

成功要求:

错误的网关请求:

请求行比较:

结果是:这是内部网络问题,因为我网络中的其他服务也遇到了同样的问题。 解决方案:在出现 HTTP 错误 502 时重新发送请求。

ProxyServlet 使用通过 null SSLContextFactory 实例化的 HttpClient。这导致套接字处理程序具有 no SSL 支持。

这在大多数情况下可能没问题,但当(可能)代理重定向到安全套接字或 SSO 服务器需要某种安全(自动)登录验证(就像人们在安全的公司网络上所期望的那样)时,它会失败.在这种情况下,最好使用支持 SSL 的 HttpClient,这样服务器通信可以根据需要 encrypted/decrypted。

重写 ProxyServlet.newHttpClient() 方法如下:

@Override
protected HttpClient newHttpClient() {
  HttpClient mHttpClient = new HttpClient(new SslContextFactory(true));
  return mHttpClient;
}