我已经将嵌入tomcat服务器的Spring Boot中的保持活动超时设置为30秒。所以我在下面的Application.java中使用
@Bean public EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() { TomcatEmbeddedServletContainerFactory containerFactory = new TomcatEmbeddedServletContainerFactory(); containerFactory .addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override public void customize(Connector connector) { ((AbstractProtocol) connector.getProtocolHandler()) .setKeepAliveTimeout(30000); } }); return containerFactory; }
然后我从我的休息控制器睡了一个请求线程40秒钟。但是,当我通过邮递员发出请求时,它成功返回HTTP状态代码200,而应返回网关超时错误。
我同时尝试了setConnectionTimeout和setKeepAliveTimeout,但它没有用。
我在这里想念什么?
编辑问题:我最初的问题
让我解释一下我的原始问题,这使我提出了上述问题。
好吧,我有一个漫长的投票过程,通常运行大约5 minits。
因此,发生什么事是当我为longpoll调用Rest API时,在经过2.2次微型操作后,我在浏览器中收到504 http错误。
我正在使用一个AWS环境,其中有一个ELB和一个安装在AWS EC2实例中的HAProxy。
根据AWS文档, ELB的默认空闲连接超时为60秒 。因此,我将其最多增加了30分钟。
而且它说,
如果使用HTTP和HTTPS侦听器,建议您为EC2实例启用keep-alive选项。 您可以在Web服务器设置 或EC2实例的内核设置中 启用保持活动状态 。
因此,将上述代码段之类的嵌入式tomcat保持活动超时时间增加到30.2分钟
因此,现在我希望我的长时间轮询请求能够完成,并且不会出现504错误。但是我在浏览器中仍然收到504错误吗?
参考:AWS开发人员指南
看来您想关闭移动设备上可能发生的废弃HTTP连接。
@RestController @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean public EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() { TomcatEmbeddedServletContainerFactory containerFactory = new TomcatEmbeddedServletContainerFactory(); containerFactory .addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override public void customize(Connector connector) { ((AbstractProtocol) connector.getProtocolHandler()).setConnectionTimeout(100); } }); return containerFactory; } @RequestMapping public String echo(@RequestBody String body) { return body; } }
连接超时已设置为100毫秒,以便快速运行测试。数据按块发送。在每个块之间,正在运行的线程被挂起x毫秒。
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = DemoApplication.class) @WebIntegrationTest("server.port:19000") public class DemoApplicationTests { private static final int CHUNK_SIZE = 1; private static final String HOST = "http://localhost:19000/echo"; @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void slowConnection() throws Exception { final HttpURLConnection connection = openChunkedConnection(); OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream()); writeAndWait(500, out, "chunk1"); writeAndWait(1, out, "chunk2"); out.close(); expectedException.expect(IOException.class); expectedException.expectMessage("Server returned HTTP response code: 400 for URL: " + HOST); assertResponse("chunk1chunk2=", connection); } @Test public void fastConnection() throws Exception { final HttpURLConnection connection = openChunkedConnection(); OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream()); writeAndWait(1, out, "chunk1"); writeAndWait(1, out, "chunk2"); out.close(); assertResponse("chunk1chunk2=", connection); } private void assertResponse(String expected, HttpURLConnection connection) throws IOException { Scanner scanner = new Scanner(connection.getInputStream()).useDelimiter("\\A"); Assert.assertEquals(expected, scanner.next()); } private void writeAndWait(int millis, OutputStreamWriter out, String body) throws IOException, InterruptedException { out.write(body); Thread.sleep(millis); } private HttpURLConnection openChunkedConnection() throws IOException { final URL url = new URL(HOST); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setChunkedStreamingMode(CHUNK_SIZE); return connection; } }
将包的日志级别设置org.apache.catalina.core为DEBUG
org.apache.catalina.core
DEBUG
logging.level.org.apache.catalina.core=DEBUG
您会看到一个SocketTimeoutException要slowConnection测试的。
SocketTimeoutException
slowConnection
我不知道为什么要使用HTTP状态代码502作为错误响应状态。HTTP 502说:
502(错误的网关)状态代码表示服务器充当网关或代理时,从尝试执行请求的过程中访问的入站服务器收到无效响应。
客户端Postman调用您的服务器应用程序。我看不到两者之间的任何网关或代理。
Postman
如果您只是将问题压缩到最低限度,而实际上您想自己构建一个代理,则可以考虑使用Netflix Zuul。
2016年3月23日更新:
这是OP关于Stackoverflow的问题的根本原因:
我对longpolling所做的事情是,从服务apihibernate线程一段时间,然后将其唤醒,然后一次又一次地执行直到直到某些数据库状态完成为止。
该实现实际上阻止了Tomcat工作线程处理新的HTTP请求。因此,每增加一个长时间运行的操作,您的请求吞吐量就会降低。
我建议将长时间运行的操作卸载到单独的线程中。客户端(浏览器)启动一个新请求以获取结果。根据处理状态,服务器将返回结果或通知/错误/警告/。
这是一个非常简单的示例:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import static org.springframework.http.HttpStatus.CREATED; import static org.springframework.http.HttpStatus.NOT_FOUND; import static org.springframework.http.HttpStatus.OK; @RestController @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } private ExecutorService executorService = Executors.newFixedThreadPool(10); private Map<String, String> results = new ConcurrentHashMap<>(); @RequestMapping(path = "put/{key}", method = RequestMethod.POST) public ResponseEntity<Void> put(@PathVariable String key) { executorService.submit(() -> { try { //simulate a long running process Thread.sleep(10000); results.put(key, "success"); } catch (InterruptedException e) { results.put(key, "error " + e.getMessage()); Thread.currentThread().interrupt(); } }); return new ResponseEntity<>(CREATED); } @RequestMapping(path = "get/{key}", method = RequestMethod.GET) public ResponseEntity<String> get(@PathVariable String key) { final String result = results.get(key); return new ResponseEntity<>(result, result == null ? NOT_FOUND : OK); } }