'API endpoint using Spring REST controller returns 404 after it is invoked

We have an eCommerce webapp with the front-end server and the API server being in separate EC2 Ubuntus. The API server exposes 168 API RESTFul endpoints using Spring MVC. Each class has the @RestController annotation. We have a problem with one of them.

When this endpoint (which is a PUT) is called by the front-end, we know that it is invoked in Spring, we see its effects in the database and the PDF file it generates, but then (every single time) it returns 404 to the browser which we see in the tomcat access logs, as well, even though it is invoked every time.. There is nothing extraordinary about this endpoint. All 168 endpoints look the same. They have the HTTP method, produces JSON and return ResponseEntity. I moved this endpoint to another new class, I changed its endpoint URI, I changed the method name, I removed everything from this method except for "return ResponseEntity.ok().body(new SomeObject())", but it always returns 404. Does Spring MVC do this or tomcat itself?

We use OpenJDK 11.0.11+9, tomcat 9.0.59, Spring Framework 5.3.16, Spring Security 5.6.2, javaee-api 8.0.1 and servlet 4.0. Here is the endpoint method:

@RestController
@RequestMapping(value = "/api/v1/drivers")
public class DriverAPIService
{
    @PutMapping(value = "/delivered", produces = "application/json")
    public ResponseEntity<OrderStatusResponseBean> markOrderAsDelivered(@RequestBody OrderStatusUpdateRequestBean requestBean, HttpServletRequest request, HttpServletResponse response, Model model)
    {
        try
        {
             return DriverService.markOrderAsDelivered(requestBean, request);
        }
        catch(Throwable e)
        {
            return ResponseEntity.badRequest().build();
        }
    }
}

Our tomcat config in the server.xml for the connectors is:

<Executor name="tomcatThreadPool" namePrefix="tomcat9-thread-" maxIdleTime="60000"
maxThreads="50" minSpareThreads="5"/>

<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" redirectPort="8443" maxConnections="100" acceptCount="300"/>

<Connector executor="tomcatThreadPool" SSLEnabled="true" maxPostSize="5000000" port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol" scheme="https"
    secure="true" compression="on" maxKeepAliveRequests="10" connectionTimeout="60000"
    maxConnections="100" acceptCount="300" enableLookups="false" connectionUploadTimeout="120000" disableUploadTimeout="false">
    <SSLHostConfig>
       <Certificate certificateFile="conf/cert.pem" certificateKeyFile="conf/privkey.pem" certificateChainFile="conf/chain.pem" />
    </SSLHostConfig>

    <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" compression="on" keepAliveTimeout="360000"/>
</Connector>


Solution 1:[1]

Let's recapitulate what we have:

  • Your service code is wrapped into a catch-all block, that will transform any inner exceptions into an http-400 response. Catch-alls are a code smell, but in this case it helps to exclude the possibility that the problem is deep in your service.
  • The service code is executed (as you say), so the method lookup generally works.

IMHO the problem must be in the response processing. I suspect the HttpServletResponse to be the problem here. There are only rare cases when it's really needed (streaming, cookies, etc.), but generally it causes more problems than it actually solves. So please remove any unneeded parameters from the method signature and try again.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 oliver_t