Pregunta

I had developed a PhoneGap app which is now being transformed to a mobile website. Everything works smoothly besides one small glitch. I use a certain third party API via a POST request, which works fine in the app, but fails in the mobile website version.

After a closer look it seems like AngularJS (I guess the browser actually) is first sending an OPTIONS request. I learned a lot today about CORS, but I can't seem to figure out how to disable it altogether. I do not have access to that API (so changes at that side are impossible), but they have added the domain I am working on to their Access-Control-Allow-Origin header.

This is the code I am talking about:

        var request = {
                language: 'fr',
                barcodes: [
                    {
                        barcode: 'somebarcode',
                        description: 'Description goes here'
                    }
                ]
            };
        }
        var config = {
            headers: { 
                'Cache-Control': 'no-cache',
                'Content-Type': 'application/json'
            }
        };
        $http.post('http://somedomain.be/trackinginfo', request, config).success(function(data, status) {
            callback(undefined, data);
        }).error(function(data, status) {
            var err = new Error('Error message');
            err.status = status;
            callback(err);
        });

How can I prevent the browser (or AngularJS) from sending that OPTIONS request and just skip to the actual POST request? I am using AngularJS 1.2.0.

¿Fue útil?

Solución

The preflight is being triggered by your Content-Type of application/json. The simplest way to prevent this is to set the Content-Type to be text/plain in your case. application/x-www-form-urlencoded & multipart/form-data Content-Types are also acceptable, but you'll of course need to format your request payload appropriately.

If you are still seeing a preflight after making this change, then Angular may be adding an X-header to the request as well.

Or you might have headers (Authorization, Cache-Control...) that will trigger it, see:

Otros consejos

As what Ray said, you can stop it by modifying content-header like -

 $http.defaults.headers.post["Content-Type"] = "text/plain";

For Example -

angular.module('myApp').factory('User', ['$resource','$http',
    function($resource,$http){
        $http.defaults.headers.post["Content-Type"] = "text/plain";
        return $resource(API_ENGINE_URL+'user/:userId', {}, {
            query: {method:'GET', params:{userId:'users'}, isArray:true},
            getLoggedIn:{method:'GET'}
        });
    }]);

Or directly to a call -

var req = {
 method: 'POST',
 url: 'http://example.com',
 headers: {
   'Content-Type': 'text/plain'
 },
 data: { test: 'test' }
}

$http(req).then(function(){...}, function(){...});

This will not send any pre-flight option request.

NOTE: Request should not have any custom header parameter, If request header contains any custom header then browser will make pre-flight request, you cant avoid it.

When performing certain types of cross-domain AJAX requests, modern browsers that support CORS will insert an extra "preflight" request to determine whether they have permission to perform the action. From example query:

$http.get( ‘https://example.com/api/v1/users/’ +userId,
  {params:{
           apiKey:’34d1e55e4b02e56a67b0b66’
          }
  } 
);

As a result of this fragment we can see that the address was sent two requests (OPTIONS and GET). The response from the server includes headers confirming the permissibility the query GET. If your server is not configured to process an OPTIONS request properly, client requests will fail. For example:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept, origin, x-requested-with, content-type
Access-Control-Allow-Methods: DELETE
Access-Control-Allow-Methods: OPTIONS
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Methods: GET
Access-Control-Allow-Methods: POST
Access-Control-Allow-Orgin: *
Access-Control-Max-Age: 172800
Allow: PUT
Allow: OPTIONS
Allow: POST
Allow: DELETE
Allow: GET

I think best way is check if request is of type "OPTIONS" return 200 from middle ware. It worked for me.

express.use('*',(req,res,next) =>{
      if (req.method == "OPTIONS") {
        res.status(200);
        res.send();
      }else{
        next();
      }
    });

Preflight is a web security feature implemented by the browser. For Chrome you can disable all web security by adding the --disable-web-security flag.

For example: "C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="C:\newChromeSettingsWithoutSecurity" . You can first create a new shortcut of chrome, go to its properties and change the target as above. This should help!

setting the content-type to undefined would make javascript pass the header data As it is , and over writing the default angular $httpProvider header configurations. Angular $http Documentation

$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top