Search code examples
spring-mvcspring-bootspring-restcontroller

Spring REST Controller is not responding to Angular request


I have an app to create server certificate requests, just as if one were using java keytool or something. I'm trying to return the created certificate request and the key in a zip file, but for the life of me, I can't get my REST controller to respond to the http request. CORRECTION: The controller responds, but the code within the method is never executed.

The server does receive the request, because my CORS filter is executed. But I have a debug set in the controller method, and it's never triggered. Is the signature of the method correct? I need another set of eyes, please?

Here is my controller code:

@RequestMapping(method = RequestMethod.POST, value = "/generateCert/")
public ResponseEntity<InputStreamResource> generateCert(@RequestBody CertInfo certInfo) {
    System.out.println("Received request to generate CSR...");

    byte[] responseBytes = commonDataService.generateCsr(certInfo);
    InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(responseBytes));

    System.out.println("Generated CSR with length of " + responseBytes.length);
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=certificate.zip")
            .contentType(MediaType.parseMediaType("application/zip"))
            .contentLength(responseBytes.length)
            .body(resource);
}

And here is the Angular request:

generateCertificate(reqBody: GenerateCert) {
   let headers = new Headers();
   headers.append('Content-Type', 'application/json');

   this.http.post(this.urlGenerateCert, JSON.stringify(reqBody), {headers: headers}).subscribe(
    (data) => {
        let dataType = data.type;
        let binaryData = [];
        binaryData.push(data);
        this.certBlob = new Blob(binaryData);
    });
    return this.certBlob;
 }

And finally, the request and response headers I copied from the Network Panel:

Response
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Authorization, Accept, X-Requested-With, remember-me
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3600
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Thu, 27 Dec 2018 22:48:00 GMT
Expires: 0
Location: http://localhost:8102/login
Pragma: no-cache
Set-Cookie: JSESSIONID=EDACE17328628D579670AD0FB53A6F35; Path=/; HttpOnly
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

Request
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 205
Content-Type: application/json
Host: localhost:8102
Origin: http://localhost:4200
Referer: http://localhost:4200/generateCerts
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36

I really struggled with getting CORS working, so maybe that's interfering with the request? I hate to post all that code unless absolutely necessary. Anybody got any ideas?


Solution

  • Thanks to everyone who contributed. I discovered the error was due to the headers of my controller method. After changing them, the method was invoked properly. This is what worked:

    @RequestMapping(method = RequestMethod.POST, path = "/generateCert", 
        produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE}, consumes = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<byte[]> generateCert(@RequestBody CertInfo certInfo) {
        byte[] responseBytes = commonDataService.generateCsr(certInfo);    
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
                .contentLength(responseBytes.length)
                .body(responseBytes);
    }