Nate Gardner
Nate Gardner

Reputation: 1717

Angular 5 Http POST request turns to OPTIONS and returns 404

Using:

import { HttpClient, HttpHeaders } from '@angular/common/http';

const httpOptions = {
    headers: new HttpHeaders({
        'Content-Type: ['application/json']
        })
    }

@Injectable()
export class MyService {
    constructor (private http: HttpClient) {}
    private myUrl = 'http://localhost:3000/my-service';
    private postBody = 
    `
    [
     { "a": ["complex"],
       "serialized": "data",
       "set": [],
      },{
       "in": "json",
       "format": []
      }
    ]
    `;

    getData(): Observable<ExpectedResponseType> {
        return this.http.post<ExpectedResponseType>(this.myUrl, this.postBody, httpOptions);
    }
}

When I subscribe to this service, the browser sends a preflight OPTIONS request to localhost:3000/my-service which returns 404. If I remove httpOptions from the request, it successfully POSTs with the body I want but doesn't set Content-Type to application/json and thus the server returns 500.

How can I send a POST request in Angular 5 with a content type of json? The server provides the expected results from Postman, but I'm not sure how to convince Angular to simply send the POST with the headers I want.

Upvotes: 1

Views: 1775

Answers (3)

Nate Gardner
Nate Gardner

Reputation: 1717

The best solution I found for development was to use an Angular proxy.

const proxy = [
  {
    context: '/api',
    target: 'http://localhost:3000',
    pathRewrite: {'^/api' : ''}
  }
];
module.exports = proxy;


ng serve --proxy-config proxy.config.js --open

This reroutes all requests on the same domain under /api back to my server so I don't need to worry about configuring my server to replace ng serve.

Upvotes: 0

Khalid
Khalid

Reputation: 161

This is happening because of CORS restrictions (Cross-Origin Resource Sharing). Browsers do not allow requests to go a server with a different host/port combination unless the server allows it. This is for security reasons (to protect against XSRF attacks for instance). There are several ways to address this:

  • Update the server to add headers that allow CORS from any origin or a given origin (This is how you'd do it in the real environment if you want to allow other servers to access your APIs). There are a lot of resources on the internet about that, this is a good example: http://restlet.com/company/blog/2016/09/27/how-to-fix-cors-problems/.
  • Add a proxy between your client and server that resolves the issue (This is hit and miss in my experience, but some frameworks like ionic have a working proxy).
  • Some browsers are less strict than others, and the most strict in this case, chrome, has a flag that allows you to bypass CORS checks during development (Use with caution, and do not access real websites while this flag is enabled because it may make you vulnerable to XSRF attacks). The flag is: --disable-web-security --user-data-dir=SOME_FOLDER.

Upvotes: 1

danday74
danday74

Reputation: 56956

The OPTIONS request is not an Angular issue, it is a browser issue.

When a browser makes a cross domain request it will (for most requests, depending on what you are requesting and method used) first do an OPTIONS request.

The purpose of the OPTIONS request is to check that the server is allowing your client (browser) to make requests to it. This is determined by the server CORS response headers. If the OPTIONS request fails, then the browser knows it is not allowed and thus does not bother to make the actual request you wanted.

This is only enforced by browsers and thus POSTMAN will work fine.

Please add the CORS headers to your server response and ensure your server supports OPTIONS requests.

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin

See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

If you really cant be bothered with CORS then send the request to the same domain and get your webserver to rewrite the URL. Note that you will have to repeat the logic for the rewrite in your prod server also.

Upvotes: 3

Related Questions