I'm implementing routing datasources in my Spring application. One of method to get lookup key is accessing HttpServletRequest and getting current domain as key by invoking method
request.getServerName()
HttpServletRequest is accessing via RequestContextHolder as below
(ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
or just by autowiring HttpServletRequest
#Autowired
private HttpServletRequest request;
Everything is working correctly when I'm in request scope, using standard #RequestMapping annotation in controller.
I want to do same thing in WebSocket method annotated by #MessageMapping. There is no request scope so Autowiring HttpServletRequest and invoking methot getServerName() gives exception as below
No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Message is passed to controller using Stomp and SockJs. Here is my configuration
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/sub");
config.setApplicationDestinationPrefixes("/some");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
And Controller
#Autowired
private SomeService service;
#MessageMapping("/someUrl/{param}")
public void subscribeForMessage(#DestinationVariable Long param) {
service.doSmth();
}
I do not want to pass it from controller to service because invocation chain is much longer and getting current lookup key have to be transparent.
It is possible to get server name in a way similiar to Autowiring HttpServletRequest? It is possible to inject some "scope" of websocket request or session without passing it ?
You have to initialize bean of RequestContextListener to request object other than #Controller ( Request scope).
#Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
Related
I have a spring boot application with SOAP endpoints and an interceptor class which implements EndpointInterceptor.The problem is, there is no overridden methods available in this interface which have access to HttpServletRequest and HttpServletResponse.
My question is :
How can I get HttpServletRequest and HttpServletResponse objects whenever an API request comes using a SOAP interceptor (I saw many examples which is using WebMvcConfigurerAdapter and HandlerInterceptor but it is working only for Rest #Controller. In my case it is SOAP with #Endpoint and it is not calling the overridden methods).
If that is not possible , how can i get make this object from MessageContext since the handleRequest overridden method is having that parameter as show below
#Override
public boolean handleRequest(MessageContext messageContext,
Object endpoint) throws Exception {
LOG.info("Endpoint Request Handling");
return true;
}
Spring-ws has TransportContext class for storing the current underlying connection. You can access it via TransportContextHolder class statically in the code.
If you are sure that the underlying connection is a HttpServletConnection then you could do something like this inside the interceptor methods:
TransportContext ctx = TransportContextHolder.getTransportContext();
HttpServletRequest req = ((HttpServletConnection) ctx.getConnection()).getHttpServletRequest();
If you want to manipulate (Override) the HttpServletRequest and HttpServletResponse
before/after reaching the endpoints using Interceptors would be a bad idea as the requests reached at that level would be preprocessed and would not give you the option of modification.
You could use Filters instead of Interceptors to achieve what your trying to do.
I am using Spring MVC. I am not using Spring boot dependencies.
I created the AuthenticationSuccessEventListener class, this class implements the ApplicationListener interface.
How do I get the HttpServletRequest in the AuthenticationSuccessEventListener class? I tried many options, but I still could not find the answer to my question.
When trying to get the HttpServletRequest, I get an exception.
Message: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Who can, tell me please, what am I doing wrong?
#Component
public class AuthenticationFailureListener implements ApplicationListener<AuthenticationSuccessEvent> {
// This option doesn't work.
// #Autowired
// HttpServletRequest httpServletRequest;
// This option doesn't work.
// HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
#Override
public void onApplicationEvent(AuthenticationSuccessEvent a) {
}
}
Building Spring Boot application, deploying(by copying to webapps folder while Tomcat is down) to local Tomcat8. Always get an error:
No thread-bound request found:
Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread?
If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet:
In this case, use RequestContextListener or RequestContextFilter to expose the current request.
As I understand, problems are while instantiating bean with WebAuthenticationDetails extending:
#Component
public class AuthDetails extends WebAuthenticationDetails{
private final AuthTarget authTarget;
public AuthDetails(HttpServletRequest request) {
super(request);
this.authTarget = AuthTarget.valueOf(request.getParameter("target"));
}
public AuthTarget getAuthTarget(){
return this.authTarget;
}
}
It cannot provide HttpServletRequest for bean constructing, but I don't know how to evade it.
Tried to add RequestContextListener, in xml or as implementation(and marking as #WebListener), no effect.
Out of ideas, how to fix it. Tried example from here: https://github.com/Baeldung/spring-security-registration , no changes - same error at the similar place.
Any help is greatly welcome.
The key was simple: I should define filter bean explicitly in security configuration extends WebSecurityConfigurerAdapter:
#Bean
AuthFilter authFilter() throws Exception{
AuthFilter authFilter = new AuthFilter();
return authFilter;
}
instead of autowiring it.
I am having issues accessing a bean that is defined with a request centric scope in a thread that is not the request's thread.
My scenario is as follows:
Execution starts from a REST request coming from a client. In this request I define a bean that allows me to access data in a DB. The location of the DB depends on the user performing the request itself, hence why the bean with which the db is accessed is bound to the request itself. I get the user details from the request's auth and use them to init the bean.
During the HTTP request the code may call to an external service over a websocket connection. The ws traffic is handled by different StompFrameHandler classes. When these handle traffic they do so on a dedicated thread, which is not the same as the initial http request (and rightfully so!).
Some of these StompFrameHandler classes need to access the DB relevant to the user in context for the current (REST) request.
At 3 is where I encounter the issue:
No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
I understand what the error is telling me and the fact that due to how I have defined my bean (request scope bound) spring does not allow me to access it in other threads. However I still need to use that db accessing bean from the ws traffic handling thread.
Here is a simplified version of my code:
The bean configuration:
#Configuration
public class DbClientRequestScopeConfiguration {
private DbClientFactoryI dbClientFactory;
private AuthenticationFacadeI authenticatedUserInfo;
#Autowired
public DbClientRequestScopeConfiguration(DbClientFactoryI dbClientFactory, AuthenticationFacadeI authenticatedUserInfo) {
this.dbClientFactory = dbClientFactory;
this.authenticatedUserInfo = authenticatedUserInfo;
}
#Bean
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public DbClientI getDbClient() {
Authentication auth = authenticatedUserInfo.getAuthentication();
return dbClientFactory.getDbClient(auth.getDetails());
}
}
The DataService using the bean (this runs in the request's thread)
#Service
public class DataService {
private DbClientI dbClient;
#Autowired
public DataService(DbClientI dbClient) {
this.dbClient = dbClient;
}
...
}
The frame handler working with the WS traffic Note that this in not initialised by Spring's context, instead it is manually initialised by a class running in the request's thread, which gives it the instance of the #DataService coming from the Context.
public class SaveDataFrameHandler implements StompFrameHandler{
private DataService dataService;
public SaveDataFrameHandler(DataService dataService) {
this.dataService = dataService;
}
#Override
public Type getPayloadType(StompHeaders headers) {
return JsonNode.class;
}
#Override
public void handleFrame(StompHeaders headers, Object payload) {
// This method will be called on a separate thread
JsonNode jsonPayload = (JsonNode) payload;
dataService.saveRecord(jsonPayload);
}
}
I am looking for suggestions on how I could actually use that bean in my ws thread or how to rearchitect the solution so that I do not run into this problem.
Thanks in advance!
UPDATE:
I have managed to get around the problem for now even though I am not 100% happy with the solution. To avoid repetition, I posted my current solution in a new question, since I am facing a different issue now still related to this code:
Proxied prototype bean is created every time a method is invoked from it
Is there any way in spring boot to grab header from request in any point of application?
Some static stuff will be great.
Please, be aware that #RequestHeader does not work for me since I need this value on service layer.
You can inject HttpServletRequest object in your service layer like this :
#Autowired
HttpServletRequest request;
private void method() {
request.getHeader("headerName");
}
but remember, that bean HttpServletRequest has HTTP request scope. So, you can't inject that into asynchronous methods etc, because it will throw Runtime Exception.
hope it helps.
I was searching the same question before, i found out that you can use header parameters in the RestController methods with #RequestHeader as you said. So why not direct them into your service layer methods:
#Autowired
ServiceLayerObj serviceLayerObj;
...
#RequestMapping
public YourReturnObj someRestServiceMethod(
#RequestBody SomeObj body,
#RequestHeader(value = "username") String username
){
return serviceLayerObj.yourServiceLayerMethod(body,username);
}