Search code examples
javascripthttpcorshttp-put

Making a PUT request results in an OPTIONS request being sent first before the PUT, why does the browser behave this way?


When i send a POST request, it's ok. But when i send a PUT request (replace $http.post() to $http.put()) Angular send an OPTIONS request without datas, wait the response and send a PUT request with datas.

It's not a CORPS problem because it's the client which send 2 requests.

For the OPTIONS request, the JSON response isn't parsed because Angular doesn't go to the success function.

I want to Angular not send the OPTIONS request. Do you know this problem ? Do you know a fix ?

The code :

var app = angular.module('myApp', []);
app.config(function($httpProvider) {
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
    $httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
    $httpProvider.defaults.useXDomain = true;
    //
    var param = function(obj) {
        var query = '', name, value, fullSubName, subName, subValue, innerObj, i;
        for(name in obj) {
            value = obj[name];
            if(value instanceof Array) {
                for(i=0; i<value.length; ++i) {
                    subValue = value[i];
                    fullSubName = name + '[' + i + ']';
                    innerObj = {};
                    innerObj[fullSubName] = subValue;
                    query += param(innerObj) + '&';
                }
            }
            else if(value instanceof Object) {
                for(subName in value) {
                    subValue = value[subName];
                    fullSubName = name + '[' + subName + ']';
                    innerObj = {};
                    innerObj[fullSubName] = subValue;
                    query += param(innerObj) + '&';
                }
            }
            else if(value !== undefined && value !== null) {
                query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
            }
        }
        return query.length ? query.substr(0, query.length - 1) : query;
    };
    // Override $http service's default transformRequest (json to application/x-www-form-urlencoded)
    $httpProvider.defaults.transformRequest = [function(data) {
        return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
    }];
});
app.controller('login', function ($scope, $http) {
    $scope.run = function() {
        var file_data = $("#file").prop("files")[0];
        var datas = {email:"[email protected]", pass:sha1("xxxxxx")};
        $http.put("http://myapi.com/user/connect", datas
            ).success(function(data, status, headers, config) {
                console.log(data);
            }).error(function(data, status, headers, config) {

            });
        return;
    }
});

The first request :

General
Remote Address:127.0.0.1:80
Request URL:http://api.wezit.local/user/connect
Request Method:OPTIONS
Status Code:200 OK

Response Headers
Access-Control-Allow-Methods:POST, GET, PUT, DELETE
Access-Control-Allow-Origin:*
Cache-Control:no-cache, must-revalidate
Connection:Keep-Alive
Content-Length:170
Content-Type:application/json;
Date:Fri, 17 Jul 2015 16:31:15 GMT
Expires:Mon, 26 Jul 1997 05:00:00 GMT
Keep-Alive:timeout=5, max=100
Pragma:no-cache
Server:Apache/2.4.10 (Fedora) PHP/5.5.25
Set-Cookie:PHPSESSID=2dj440b2vr2emi5ht9ojcl8gk6; path=/
Set-Cookie:PHPSESSID=q3pg80qb43ps6tpkljlvelo0k7; path=/
X-Powered-By:PHP/5.5.25

Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:PUT
Connection:keep-alive
Host:api.wezit.local
Origin:http://test.local
Referer:http://test.local/api.php
User-Agent:Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.125 Safari/537.36

The second request :

General
Remote Address:127.0.0.1:80
Request URL:http://api.wezit.local/user/connect
Request Method:PUT
Status Code:200 OK

Response Headers
Access-Control-Allow-Methods:POST, GET, PUT, DELETE
Access-Control-Allow-Origin:*
Cache-Control:no-cache, must-revalidate
Connection:Keep-Alive
Content-Length:327
Content-Type:application/json;
Date:Fri, 17 Jul 2015 16:31:15 GMT
Expires:Mon, 26 Jul 1997 05:00:00 GMT
Keep-Alive:timeout=5, max=99
Pragma:no-cache
Server:Apache/2.4.10 (Fedora) PHP/5.5.25
Set-Cookie:PHPSESSID=18jfhgq2fs1p1f1nu7ua1ap8c3; path=/
Set-Cookie:PHPSESSID=14aifglpntf8amavkipclvom67; path=/
X-Powered-By:PHP/5.5.25

Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:142
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Host:api.wezit.local
Origin:http://test.local
Referer:http://test.local/api.php
User-Agent:Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.125 Safari/537.36

Form Data
email:[email protected]
pass:ce35927f4dcb044bceda5f385823419cb0156507

Solution

  • Browsers always make a pre-flight request with the OPTION method, when you initiate a cross-origin request. That means the API you are trying to access is on a different origin from your application. There's nothing you can do about this.

    Do you know this problem?

    There is no problem in what you observed, it is the expected behaviour.

    When i send a POST request, it's OK.

    Here's the reason why it's OK:

    In particular, a request is preflighted if:

    • It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
    • It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)