100

我开发了一个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);
        });

如何防止浏览器(或 AngularJS)发送该 OPTIONS 请求而直接跳到实际的 POST 请求?我正在使用 AngularJS 1.2.0。

提前致谢。

4

6 回答 6

110

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

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

或者您可能有会触发它的标头(授权、缓存控制...),请参阅:

于 2014-04-09T16:35:59.243 回答
16

正如雷所说,您可以通过修改 content-header 来阻止它 -

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

例如 -

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'}
        });
    }]);

或者直接打电话——

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

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

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

注意:请求不应有任何自定义标头参数,如果请求标头包含任何自定义标头,则浏览器将发出飞行前请求,您无法避免。

于 2015-11-30T05:00:10.340 回答
2

我认为最好的方法是检查请求是否属于“OPTIONS”类型,从中间件返回 200。它对我有用。

express.use('*',(req,res,next) =>{
      if (req.method == "OPTIONS") {
        res.status(200);
        res.send();
      }else{
        next();
      }
    });
于 2017-10-20T23:54:51.410 回答
2

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

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

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

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
于 2016-03-18T14:10:36.893 回答
0

Preflight 是浏览器实现的网络安全功能。对于 Chrome,您可以通过添加 --disable-web-security 标志来禁用所有网络安全。

例如: "C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="C:\newChromeSettingsWithoutSecurity" 。您可以先创建一个新的chrome快捷方式,转到其属性并如上所述更改目标。这应该有帮助!

于 2019-07-03T10:02:58.163 回答
-2

将内容类型设置为 undefined 将使 javascript 按原样传递标头数据,并覆盖默认的角度 $httpProvider 标头配置。Angular $http 文档

$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure);
于 2016-06-17T12:23:51.747 回答