remyml
remyml

Reputation: 91

Problem with PATCH method and CORS preflight request

I have a problem with the application I’m developing. The API is in PHP Symfony 4 and the application is made with Ionic 4.

I have a problem when doing PATCH requests. The request works very well on POSTMAN, as well as on my phone but I have problems with CORS when trying on browser (Google Chrome, Firefox).

I have inquired and I have understood that a PATCH request first goes through a pre-flight request and therefore sends a request with the OPTIONS method to my API.

I managed this method and returned a code 200 then I allowed the correct headers in my index.php file as follows:

header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header("Access-Control-Allow-Methods: GET, HEAD, PATCH, OPTIONS, POST, PUT");

At the beginning, I had a first error which indicated that the request did not return code 200, so I managed the OPTIONS method in my API. Then I have the following error:

No 'Access-Control-Allow-Origin' header is present on the requested resource.

This is strange because the error there did not appear before, and all the other requests work.

In addition, I tried with POSTMAN and the OPTIONS method returns the correct headers.

Can you help me?

Sorry about the rough English.

Upvotes: 2

Views: 4482

Answers (2)

Mic
Mic

Reputation: 4004

For anyone who finds this in this future, I've reproduced these exact symptoms, and solved my issue. The short answer is that when the method is specified on the client-side (e.g. in the fetch options), PATCH specifically is case-sensitive while other methods are not. It needs to be capitalized.

The explanation, to the best I've been able to deduce, is that even though the RFC7230 states that methods should be uppercase, they are also case-sensitive. The browsers smooth over this by automatically capitalizing several of them, I believe based on RFC7231 which defines many of the common methods, but does not define PATCH. Consider the following request initiated from the client side.

fetch('https://stackoverflow.com', 
  { method: 'post', 
    body: JSON.stringify({message: 'testing a cors issue'}), 
    headers:  {'Content-Type': 'application/json'}
  }
)

The normal behavior for at least a Chromium browser is to automatically capitalize the method in the Access-Control-Request-Method header of the CORS preflight, regardless of the capitalization my JavaScript uses in the fetch call.

Preflight request with capitalized post method

Likewise, if the method is DELETE, the browser will also automatically capitalize it in the preflight.

However, I found that the PATCH method (defined later in RFC5789) is treated like a custom HTTP method, in that it is not forcibly capitalized. It is therefore case-sensitive, which is observable during CORS preflights. If the client app specifies it in lowercase patch, that's how it appears in the Access-Control-Request-Method header, and if it's capitalized PATCH it appears capitalized in the header.

Preflight showing lowercase patch method

When you select the PATCH method within Postman, it's always capitalized, which masks the root cause of the issue. Even though the error message is in regard to the Access-Control-Allow-Origin header, the root cause that I've seen is the method's case-sensitivity.

Upvotes: 10

UserHelpNeeding02356
UserHelpNeeding02356

Reputation: 275

Environement info-
   ionic (Ionic CLI)             : 4.0.0 
   Ionic Framework               : @ionic/angular 4.0.0
   @angular-devkit/build-angular : 0.8.6
   @angular-devkit/schematics    : 0.8.6
   @angular/cli                  : 6.2.6
   @ionic/angular-toolkit        : 1.1.0

For fixing CORS error you should follow this steps:

  1. Create into your Ionic project (in the root)a file call it: proxy.conf.json write this(copy/paste) inside:
"/api/*": {  
    "target": "http://myremoteserver/api",  
    "secure": false,  
    "logLevel": "debug"  
}
  1. Open your angular.json file and set the line proxyConfig": "proxy.conf.json" as you can see below into "serve":

    "serve": {
              "builder": "@angular-devkit/build-angular:dev-server",
              "options": {
                "browserTarget": "app:build",
                proxyConfig": "proxy.conf.json"
              },
              "configurations": {
                "production": {
                  "browserTarget": "app:build:production"
    
  2. Open your package.json and add this line into the script array :

    "start": "ng serve --port 8100 --proxy-config proxy.conf.json" 
    

    you shold get something like this (see below) :

    "scripts": {
        "ng": "ng",
        "start": "ng serve --port 8100 --proxy-config proxy.conf.json",
        "build": "ng build",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e"
      }
    
  3. After in your command line run this command : npm run start

If you followed this steps it's should be OK

For my part it's working !!!

Best regards

Upvotes: 0

Related Questions