我有一個 Spring Boot 2.7.3 應用程式,定義了以下控制器:
@RestController
@EnableAutoConfiguration
public class TrainController {
@CrossOrigin(origins = "http://localhost:3000")
@RequestMapping(value = "/trains/history", method = RequestMethod.GET)
public List<TrainStatus> getTrainStatusesForTimestamp(
@RequestParam long timestamp
) {
// do stuff
}
}
呼叫此 API 端點通常作業得很好,當然當我在本地運行應用程式時,但在負載較重的生產環境中,例如重復呼叫此 API 端點與我的應用程式跨多個控制器定義的其他 API 端點的大量呼叫并行,我開始在我的日志中看到這樣的訊息:
2022-09-06 20:48:37.939 DEBUG 19282 --- [https-openssl-nio-443-exec-10] o.s.w.f.CommonsRequestLoggingFilter : Before request [GET /trains/history?timestamp=1662511707]
2022-09-06 20:48:37.945 WARN 19282 --- [https-openssl-nio-443-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'timestamp' for method parameter type long is not present]
2022-09-06 20:48:37.945 DEBUG 19282 --- [https-openssl-nio-443-exec-10] o.s.w.f.CommonsRequestLoggingFilter : After request [GET /trains/history?timestamp=1662511707]
(CommonsRequestLoggingFilter除錯日志行來自我根據此檔案定義的 bean ;我很好奇是否確實定義了所需的timestamp引數,這就是我添加它的原因。)
此外,當MissingServletRequestParameterException拋出這些錯誤例外時,回應是 400 Bad Request。我已經從客戶端確認了timestamp確實作為請求引數包含在內的事情,并且 Spring Boot 應用程式日志似乎證實了這一點,但我在重負載下間歇性地看到這些例外。
這是怎么回事?我是否達到了 Tomcat 或其他東西定義的某種連接或執行緒限制?據我所知,該應用程式在記憶體方面有很多額外的空間。
提前感謝任何人可以提供的任何幫助!
作為參考,以下是我發現的一些明顯相似的問題:
- 是否存在 QueryString 但 HttpServletRequest.getParameterMap() 為空的情況?
uj5u.com熱心網友回復:
在閱讀了這篇博文之后,我相信我已經弄清楚發生了什么:我有另一個過濾器PublicApiFilter在一組單獨的 API 端點上運行,它異步呼叫一個函式,我在其中傳遞請求物件,即的實體HttpServletRequest,進入它并呼叫它提供的各種方法。對這些請求的這些異步操作似乎正在影響后續請求,甚至是對未涵蓋的其他PublicApiFilterAPI 端點的請求。通過洗掉我正在使用的注釋,我能夠簡單地使這個函式的呼叫同步而不是異步@Async,現在問題似乎已經解決了!
以下是我的一些代碼片段,以防有一天它對其他人有用:
@EnableScheduling
@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
@EnableAsync
public class Application implements WebMvcConfigurer, AsyncConfigurer {
// ...
@Override // AsyncConfigurer
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(1);
executor.setQueueCapacity(1);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
@Override // AsyncConfigurer
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
@Component
public class PublicApiFilter extends GenericFilterBean {
private final PublicApiService publicApiService;
@Autowired
public PublicApiFilter(PublicApiService publicApiService) {
this.publicApiService = publicApiService;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// ...
chain.doFilter(request, response);
this.publicApiService.logRequest(httpRequest);
}
}
@Service
public class PublicApiService {
// ...
@Async // <- simply removing this annotation appears to have done the trick!
public void logRequest(HttpServletRequest request) {
// invoke request.getRequestURI(), request.getHeader(...), request.getRemoteAddr, and request.getParameterMap() for logging purposes
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/506446.html
