如何跳过AngularJS中的OPTIONS预检请求

Bra*_*lle 82 post cors angularjs

我开发了一个PhoneGap应用程序,现在正在转换为移动网站.除了一个小小的故障外,一切顺利.我通过POST请求使用某个第三方API,这在应用程序中运行良好,但在移动网站版本中失败.

仔细看后,似乎AngularJS(我猜浏览器实际上)是先发送一个OPTIONS请求.我今天学到了很多关于CORS的知识,但我似乎无法弄清楚如何完全禁用它.我无权访问该API(因此无法进行更改),但他们已将我正在处理的域添加到其Access-Control-Allow-Origin标头中.

这是我正在谈论的代码:

        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);
        });
Run Code Online (Sandbox Code Playgroud)

如何阻止浏览器(或AngularJS)发送OPTIONS请求并跳转到实际的POST请求?我正在使用AngularJS 1.2.0.

提前致谢.

Ray*_*lus 98

预检由您的内容类型触发application/json.防止这种情况的最简单方法是将Content-Type设置为text/plain您的情况.application/x-www-form-urlencoded&multipart/form-dataContent-Types也是可以接受的,但您当然需要适当地格式化您的请求有效负载.

如果您在进行此更改后仍然看到预检,那么Angular也可能会在请求中添加X-header.

或者您可能有触发它的标题(Authorization,Cache-Control ...),请参阅:

  • 自定义标题也会触发预检. (11认同)
  • 这是正确答案 - 您的Content-Type和Cache-Control标头正在触发预检请求.具有Content-Type of text/plain和其他一些内容的普通GET是触发非预先请求的唯一方法.请参阅:HTTPS://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS#Preflighted_requests (9认同)
  • 更改内容类型以阻止选项测试并不是答案。内容类型应与内容类型匹配,无论 (5认同)

Viv*_*vex 15

正如雷所说,你可以通过修改内容标题来阻止它 -

 $http.defaults.headers.post["Content-Type"] = "text/plain";
Run Code Online (Sandbox Code Playgroud)

例如 -

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'}
        });
    }]);
Run Code Online (Sandbox Code Playgroud)

或直接致电 -

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

$http(req).then(function(){...}, function(){...});
Run Code Online (Sandbox Code Playgroud)

这不会发送任何飞行前选项请求.

注意:请求不应该有任何自定义标头参数,如果请求标头包含任何自定义标头,那么浏览器将进行飞行前请求,您无法避免它.


M.V*_*oid 5

执行某些类型的跨域 AJAX 请求时,支持 CORS 的现代浏览器将插入额外的“预检”请求,以确定它们是否有权执行该操作。\n来自示例查询:

\n\n
$http.get( \xe2\x80\x98https://example.com/api/v1/users/\xe2\x80\x99 +userId,\n  {params:{\n           apiKey:\xe2\x80\x9934d1e55e4b02e56a67b0b66\xe2\x80\x99\n          }\n  } \n);\n
Run Code Online (Sandbox Code Playgroud)\n\n

通过该片段,我们可以看到该地址发送了两个请求(OPTIONS 和 GET)。来自服务器的响应包含确认查询 GET 权限的标头。如果您的服务器未配置为正确处理 OPTIONS 请求,客户端请求将失败。例如:

\n\n
Access-Control-Allow-Credentials: true\nAccess-Control-Allow-Headers: accept, origin, x-requested-with, content-type\nAccess-Control-Allow-Methods: DELETE\nAccess-Control-Allow-Methods: OPTIONS\nAccess-Control-Allow-Methods: PUT\nAccess-Control-Allow-Methods: GET\nAccess-Control-Allow-Methods: POST\nAccess-Control-Allow-Orgin: *\nAccess-Control-Max-Age: 172800\nAllow: PUT\nAllow: OPTIONS\nAllow: POST\nAllow: DELETE\nAllow: GET\n
Run Code Online (Sandbox Code Playgroud)\n