response sendRedirect giving 404 error - servlets

I am trying to redirect to an error page upon some condition in my servlet code. But until now nothing is working out.
So I am using weblogic 10.x as my app server. am deploying apps directly into managed servers using the console.
So basically i jar them up as .war files and deploy them as webapps.
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws IOException , ServletException
{
try
{
throw new Exception("503_Exception") ;
}
catch(Exception e)
{
response.sendRedirect(response.encodeRedirectURL(HandleError.handle(e, request)));
}
}
public class HandleError{
public static String handle(Throwable t, javax.servlet.http.HttpServletRequest request)
{
String sErrorMsg = t.getMessage();
if (sErrorMsg.equals("503_Exception")) {
request.setAttribute("msg", "INVALID SESSION");
return "/jsp/error/custom.html";
}
return "/default_error.html";
}
}
war file structure
->jsp->error->custom.html
->web-inf
->web-inf->classes->project2->Class1.class
http://machineNAME:3030/Application3-Project2-context-root ->redirects to ->http://machineNAME:3030/jsp/error/custom.html -->> where the actual context root is missing ..
Error 404--Not Found From RFC 2068
Hypertext Transfer Protocol --
HTTP/1.1:
10.4.5 404 Not Found
The server has not found anything
matching the Request-URI. No
indication is given of whether the
condition is temporary or permanent.
If the server does not wish to make
this information available to the
client, the status code 403
(Forbidden) can be used instead. The
410 (Gone) status code SHOULD be used
if the server knows, through some
internally configurable mechanism,
that an old resource is permanently
unavailable and has no forwarding
address.
But if i give -
response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + HandleError.handle(e, request)));
i get Error 310 (net::ERR_TOO_MANY_REDIRECTS): in chrome and in FF error says too many re-directions .
Could someone help me out ?
thanks in advance. :)

Appending request.getServletContext().getContextPath() in the beginning is a fine way to do it. But you are obviously entering an endless redirection loop. Do not forget to log your exceptions. Thus you will be able to see what the problem is.

Related

Production net6 Api rest returns html when it should return a json

I am having a problem after publishing an application to a server, IIS, net6, Angular. In development, the APIs return a JSON adjusted to the type of response that is included, but after publishing them, they return an HTML in their error varieties. This initially occurs in Authentication, which you do through Microsoft authentication to Azure.
[HttpGet, ActionName("")]
[Authorize(AuthenticationSchemes = Microsoft.AspNetCore.Authentication.AzureAD.UI.AzureADDefaults.BearerAuthenticationScheme)]
public ActionResult<Collection<MenuActive>> ActiveMenu()
{
try
{
var menu= _menuservice.GetActivemenu();
return Ok(menu);
}
catch (Exception ex)
{
//loggear exeptions
return StatusCode((int)HttpStatusCode.InternalServerError, new DetalleRespuesta() { Detalle = "Error Get Active menu", Resultado = EnumResultado.RESULTADO_FALLA });
}
}
The previous code in development, in case of bad authentication or an authentication error, returns a 401 captured by the catch, which is:
But when you publish it, it becomes the following HTML response:
I don't understand the variation of result. I suppose it has to do with the fact that when I authenticate you, I enter another page and there is the error due to bad authentication, and this is the error that returns, a page, and not a status code as expected. I appreciate any help.
maybe in Program.cs or similar cs files there is a special setting for
Development or Production mode where certain parameters are set different (e.g. allowing http/https only in development)
(like here: How to check whether the code is running in development or Production mode in Program.cs file in ASP.NET CORE 2.1?)

Client-Server communication in REST, Spring (RestTemplate): getting 404 error

I am trying to setup a Client-Server communication in REST, Spring.
In the client side I have the code:
Map<String, Double> variable = new HashMap<String, Double>(1);
variable.put(newTicket.getMovieName(),newTicket.getTicketPrice());
try{
Boolean rresult = restTemplate.getForObject("http://localhost:8081/SpringMVCMerchant/movieTheater.htm", Boolean.class, variable);
In the server side I have the code (to receive the above 'variable', and get the below boolean as a return object):
#ResponseBody
#RequestMapping(value="/movieTheater/", method=RequestMethod.GET)
public boolean getCustomerInput(Map<String, Double> input) {
return transactionService.addTransaction(input);
}
I am not sure if the above syntax is correct. When I am running the two servers, I am getting the following error at the client side(8080):
GET request for "http://localhost:8081/SpringMVCMerchant/movieTheater.htm" resulted in 404 (Not Found); invoking error handler
Please let me know what I am missing here, and what changes I need to make in my code.
Thanks in advance!
I guess you are using the wrong url to call the Web Service
http://localhost:8081/SpringMVCMerchant/movieTheater.htm
This ends with .htm whereas your RequestMapping does not contains this request pattern
Update:
Make sure there no console errors and also, if your server application is running on 8081.

Performing redirects in ServiceStack

I'm attempting to build a service in ServiceStack whose sole responsibility will be to interpret requests, and send a redirect response. Something like this:
[Route("/redirect/", "POST")
public class Redirect : IReturnVoid
{
public string Something { get; set; }
}
public class RedirectService : Service
{
public object Post(Redirect req)
{
// make some decisions about stuff
return new HttpResult(){ StatusCode = HttpStatusCode.Redirect, Headers = {{HttpHeaders.Location, "place"}}};
}
}
I did initial testing using fiddler, setting a content-type of application/json and creating an appropriate request body.This did exactly as expected: the service request gave a 302 response and redirected to the expected location.
I've also tested this by using a basic Html form post, with an action of http://myserviceuri/redirect/, which also works as expected and redirects appropriately.
However, i've hit an issue when attempting to use the SS c# client to call the same service. If I call the following code in an aspx code behind or an mvc controller
var client = new JsonServiceClient("uri);
client.post(new Redirect{Something = "something});
I get a 500 and the error message:
The remote certificate is invalid according to the validation procedure.
Which makes sense as it's a development server, with a self-cert. But I get the feeling that, as I can call the service successfully by other means, that this is a red herring.
Should I be using a different type of c# client to make the request, or setting any more custom headers, or something else? Am I fundamentally not understanding what i'm trying to do?
Please let me know if more info is needed. Thanks.
What's happening here is that the JsonServiceClient is happily following the redirect, doing more than what you've expected it to do.
I'll reference a related question and answer for posterity ( - hopefully you've resolved this issue a long time ago...).
POST to ServiceStack Service and retrieve Location Header
Essentially you'd use .net's WebRequest or the ServiceStack extensions mentioned in the answer to see the redirect and act as you see fit.

jetty webSocket : java.lang.IllegalStateException: Committed

I am using Jetty Websockets in my Web Application .
When i am trying to redirect to a logoff jsp , i am getting this error
oejs.ServletHandler:/test
java.lang.IllegalStateException: Committed
at org.eclipse.jetty.server.Response.resetBuffer(Response.java:1069)
at javax.servlet.ServletResponseWrapper.resetBuffer(ServletResponseWrapper.java:232)
at org.eclipse.jetty.http.gzip.GzipResponseWrapper.resetBuffer(GzipResponseWrapper.java:273)
at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:199)
at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:98)
This is the way i am redirecting
RequestDispatcher rd = request.getRequestDispatcher("logoff.jsp");
rd.forward(request, response);
This error is not reproduceble , but could you please tell me when it may occur??
java.lang.IllegalStateException: Committed
I thought I'd provide a more general explanation of what the exception means. First off, Jetty should be ashamed by the exception message. It provides little to no help to the developer unless they already know what it actually means. The exception should be something like:
java.lang.IllegalStateException: Response headers have already been sent. Are you trying to return a result after sending content?
Typically this exception happens when you go and call:
resp.getOutputStream(); // or getWriter()
and then later try to do a redirect or something:
resp.sendRedirect("/someOtherUrl");
// or
return new ModelAndView("redirect:/someOtherUrl");
Once you get the OutputStream or Writer so you can write body bytes to the client, Jetty has to commit the response and send the HTTP 200 and associated headers, so it can start returning the body bytes. Once that happens, you then can't do a redirect nor make any other changes to the status code or headers.
The proper thing to do, once you return body bytes, is to return null from the handler instead of a ModelAndView(...) or just change the handler to return void.
You also get this exception when you call the super method in your own method implementation.
Example:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
super.doPost(req, resp); // <-- THIS IS THE PROBLEM
resp.sendRedirect("/someOtherUrl");
}
This occurs because your response has already processed a redirect request, you are trying to modify a committed response.
There are two general ways to solve this:
find out where the first redirect is and try to modify the logic to prevent the "two redirect" scenario from happening.
put a "return" after each of your redirect (personally I recommend this solution).
The reason on my side is using jetty with wrong url:
right: http://localhost:8080
wrong: http://localhost:8080/test
Consider you are running javax.servlet.Filter on Jetty server, and you face the same exception. The issue here can be described exactly as Gray's description (Thanks Gray). Typically this exception happens when you go and call:
resp.getOutputStream(); // or getWriter()
then
chain.doFilter(request, response);
If you called resp.getOutputStream();, make sure you are not using chain.doFilter(request, response); on the same request.
In my case I had some repository in my #Service and I declared it as RepositoryFoo repositoryFoo;, in the beginning of my class
I forgot to add #Autowired or even make it private, so it compiled fine and then when running I had this java.lang.IllegalStateException: Committed ... I wasted some time before figuring out the reason !

How to you get server information in HTTP response header for Apache Tomcat

We have n number of servers behind a load balancer. When a http request comes in, it is routed to one of the servers by round robin method. My question is, is there any way we can send the sever information in http response(The server to which the request is directed to) ?
If you have the information you want (IP address? some friendly name for the server?) you can easily just set the header using response.setHeader("Backend-Machine", "ServerName").
The real question is how to get that information. Most servers have multiple NICs which means you can't just pick one randomly and return the IP address (you're liable to get 127.0.0.1 which doesn't help anyone). If this is important to you, I'd recommend setting a system property on JVM launch that includes whatever string you think identifies the server. Then, write a Filter that just adds that string to every response.
Short answer on the sub-question "Where do you get the info".
TLDR;
say in: /opt/tomcat-<your_version>/lib$ execute:
java -cp catalina.jar org.apache.catalina.util.ServerInfo
You will get something like this, which is probably what you are looking for. I would pare it down to only what you need since the format essentially is just K/Vs, one per line, with colon as the delimiter.
Server version: Apache Tomcat/8.5.59
Server built: Oct 6 2020 16:57:18 UTC
Server number: 8.5.59.0
OS Name: Linux
OS Version: 5.4.0-72-generic
Architecture: amd64
JVM Version: 1.8.0_292-8u292-b10-0ubuntu1~20.04-b10
JVM Vendor: Private Build
I cannot believe this is so difficult. There should be just some Tomcat property that would allow it to tack the ServerInfo to the response, most likely in the "Server" response header.
Anyhow, since I have been digging for this, I have to say
Christopher Schultz
below is correct about the filter that needs to be added to the application. At least that would solve the problem for the given application. But how about the rest of the apps running on the same server (deployed WARs). Add a filter to each one? Sounds redundant. Here is a sample code snippet, though (you can see the original post here), many thanks to Maciej Walkowiak:
#Bean
public Filter myFilter() {
return new Filter() {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final HttpServletResponse res = (HttpServletResponse) servletResponse;
res.addHeader("Server", "my very custom server");
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
}
};
}
And for the brave, here is the source of it. You can open this class in IntelliJ org.apache.catalina.util.ServerInfo, which will reveal:
Just grab the calls that you are interested in and populate what they return in you the Server header that you create in your Spring MVC filter.
And then the ServerInfo.properties, you can see just three of them:
Personally, I set the server header like so in application.properties of my Spring Boot project:
server.server-header="Servlet engine: [Apache Tomcat/9.0.58]"
This solves the issue on a server level and I don't need to touch the code for this included - tested in FireFox Developer Tools, network tab.

Resources