当前位置: 首页 > 知识库问答 >
问题:

Springboot TomcatEmbeddedServletContainer KeepAliveTimeout不工作

司徒焕
2023-03-14

我已经将spring boot嵌入式tomcat服务器中的保持活动超时设置为30秒。因此,我在应用程序中使用下面的内容。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;
}

然后我从我的Rest控制器Hibernate一个请求线程40秒。但是当我通过postman发出请求时,它成功返回HTTP状态代码200,而不是返回网关超时错误。

我尝试setConnectionTimeout和setKeepAliveTimeout,但它不起作用。

我错过了什么?

编辑问题:我最初的问题

让我解释一下我最初的问题,这使我提出了上述问题。

我有一个很长的投票过程,通常运行大约5分钟以上。

所以发生的事情是,当我调用的Rest API的长民意调查,2.2分钟后,我得到一个504超文本传输协议错误的浏览器。

我正在使用AWS环境,其中我有一个ELB和一个HAProxy,安装在AWS EC2实例中。

根据AWS文件,ELB的默认空闲连接超时为60秒。所以我把它增加到30分钟。

而且它说,,

如果使用HTTP和HTTPS侦听器,我们建议为EC2实例启用保活选项。您可以在Web服务器设置或EC2实例的内核设置中启用保活。

因此,将嵌入式tomcat保持存活超时(如上面的代码片段)增加到30.2分钟

所以现在我希望我的长投票请求可以完成,而不会出现504的错误。但我仍然得到504错误在浏览器?

参考: AWS开发指南

共有1个答案

贺自明
2023-03-14

看起来您想关闭可能发生在移动设备上的废弃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设置日志级别。阿帕奇。卡塔琳娜。核心至调试

logging.level.org.apache.catalina.core=DEBUG

对于slowConnection测试,您可以看到一个SocketTimeoutException

我不知道为什么您希望HTTP状态代码502作为错误响应状态。HTTP 502说:

502(坏网关)状态代码表示服务器在充当网关或代理时,从试图完成请求时访问的入站服务器收到了无效响应。

客户端Postman调用服务器应用程序。我没有看到中间有任何网关或代理。

如果你只是把你的问题浓缩到最低限度,在现实中你想建立一个你自己的代理,你可以考虑使用Netflix ZUUL。

更新日期:2016年3月23日:

这就是OP对Stackoverflow提出问题的根本原因:

我对longpolling所做的是,从服务api中,我让线程Hibernate一段时间,然后唤醒它,然后一次又一次地这样做,直到某个db状态完成。

该实现实际上阻止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);
    }
}
 类似资料:
  • 我想在菜单栏文本被选中时更改它的颜色。 这里可能出了什么问题? 我尝试使用伪类':active',但没有得到应用。其中as':Hover'正在工作。 我还尝试使用'Router LinkActive',它应该添加类'Active-Link',但这也不起作用。 我在下面给出了HTML、SCCS和TS代码:

  • 我编写了一组简单的类,向一位朋友演示如何为AOP(而不是xml配置)使用注释。我们无法使@ComponentScan工作,并且AnnotationConfigApplicationContext getBean的行为也不正常。我想明白两件事。请参阅下面的代码: PersonOperationSI.java PersonOperations.java PersonOperationsConfigCl

  • 我正在Eclipse Neon中使用Hibernate工具(JBoss tools 4.4.0.Final)。现在,我想将数据库表反向工程为POJO对象和Hibernate映射文件。 我遵循了一些关于如何设置Eclipse来生成POJO对象的教程。在我运行配置之前,一切看起来都很好。什么都没发生,也没有抛出错误。有人能帮我吗?数据库是一个微软SQL服务器2014。 我的逆向工程配置文件看起来像:

  • 我正在尝试使用codeigniter insert\u batch将多行插入到我的数据库表中。根据错误报告,似乎没有设置表列。只是阵列的数量: 我的看法是: 我的控制器: 和型号:

  • 我尝试使用StreamWriter.WriteLine(不是静态地)将几行代码一次写到。txt文件中。 每个播放器对象都是字符串cosnatants。如果我使用不同的文件名(也称为BasicTestInfo2.txt),它会在bin.debug中创建该文件,但它是空的。我知道我到达了using块的内部(我在里面放了一个console.writeline),我知道我想要截断,这就是为什么我对appe

  • 我正在尝试使用yii2邮件组件发送电子邮件。 配置web。php 还有我的代码。 我收到了这个错误。 Swift\u TransportException预期响应代码为250,但收到代码“535”,消息“535-5.7.8用户名和密码不被接受。有关详细信息,请访问535 5.7.8https://support.google.com/mail/?p=BadCredentialsa13-v6sm41

  • 问题内容: 似乎不起作用,但确实起作用。有什么想法吗? 问题答案: 您不能在Java中将基本类型用作通用参数。改为使用: 使用自动装箱/拆箱,代码几乎没有区别。自动装箱意味着您可以编写: 代替: 自动装箱意味着将第一个版本隐式转换为第二个版本。自动拆箱意味着您可以编写: 代替: 如果未找到键,则隐式调用意味着将生成一个,例如: 原因是类型擦除。例如,与C#不同,泛型类型不会在运行时保留。它们只是显