首页 文章

AngularJS为跨源资源执行OPTIONS HTTP请求

提问于
浏览
252

我正在尝试设置AngularJS与跨源资源进行通信,其中传递我的模板文件的资产主机位于不同的域上,因此角度执行的XHR请求必须是跨域的 . 我已经为我的服务器添加了适当的CORS标头,以便使这项工作成功,但它似乎不起作用 . 问题是,当我在浏览器(chrome)中检查HTTP请求时,发送到资产文件的请求是OPTIONS请求(它应该是GET请求) .

我发出了一个OPTIONS HTTP请求,所以看起来浏览器试图找出是否"allowed"在执行GET请求之前先下载资产 . 如果是这种情况,那么我是否还需要为资产主机设置CORS标头(Access-Control-Allow-Origin:http://asset.host.. . )?

13 回答

  • 2

    如果您使用Jersey for REST API,则可以执行以下操作

    您不必更改Web服务实现 .

    我将为Jersey 2.x解释

    1)首先添加一个ResponseFilter,如下所示

    import java.io.IOException;
    
    import javax.ws.rs.container.ContainerRequestContext;
    import javax.ws.rs.container.ContainerResponseContext;
    import javax.ws.rs.container.ContainerResponseFilter;
    
    public class CorsResponseFilter implements ContainerResponseFilter {
    
    @Override
    public void filter(ContainerRequestContext requestContext,   ContainerResponseContext responseContext)
        throws IOException {
            responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
            responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
    
      }
    }
    

    2)然后在web.xml中,在jersey servlet声明中添加如下

    <init-param>
            <param-name>jersey.config.server.provider.classnames</param-name>
            <param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
        </init-param>
    
  • 4

    NOTE: 不确定它是否适用于最新版本的Angular .

    ORIGINAL:

    也可以覆盖OPTIONS请求(仅在Chrome中测试):

    app.config(['$httpProvider', function ($httpProvider) {
      //Reset headers to avoid OPTIONS request (aka preflight)
      $httpProvider.defaults.headers.common = {};
      $httpProvider.defaults.headers.post = {};
      $httpProvider.defaults.headers.put = {};
      $httpProvider.defaults.headers.patch = {};
    }]);
    
  • 0

    对于Angular 1.2.0rc1,您需要添加resourceUrlWhitelist .

    1.2: 发布版本他们添加了一个escapeForRegexp函数,因此您不再需要转义字符串 . 您可以直接添加网址

    'http://sub*.assets.example.com/**'
    

    确保为子文件夹添加** . 这是一个工作的jsbin for 1.2:http://jsbin.com/olavok/145/edit


    1.2.0rc: 如果您仍然使用rc版本,Angular 1.2.0rc1的解决方案如下:

    .config(['$sceDelegateProvider', function($sceDelegateProvider) {
         $sceDelegateProvider.resourceUrlWhitelist(['self', /^https?:\/\/(cdn\.)?yourdomain.com/]);
     }])
    

    这是一个jsbin示例,它适用于1.2.0rc1:http://jsbin.com/olavok/144/edit


    Pre 1.2: 对于旧版本(ref http://better-inter.net/enabling-cors-in-angular-js/),您需要在配置中添加以下2行:

    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
    

    这是一个jsbin示例,它适用于1.2之前的版本:http://jsbin.com/olavok/11/edit

  • 0

    如果你使用的是nodeJS服务器,你可以使用这个库,它对我来说很好https://github.com/expressjs/cors

    var express = require('express')
      , cors = require('cors')
      , app = express();
    
    app.use(cors());
    

    然后你可以做 npm update .

  • 10

    OPTIONS请求绝不是AngularJS错误,这就是跨源资源共享标准要求浏览器行为的方式 . 请参阅此文档:https://developer.mozilla.org/en-US/docs/HTTP_access_control,其中"Overview"部分中的内容如下:

    跨源资源共享标准的工作原理是添加新的HTTP标头,允许服务器描述允许使用Web浏览器读取该信息的起源集 . 此外,对于可能对用户数据造成副作用的HTTP请求方法(特别是;对于GET以外的HTTP方法,或对某些MIME类型的POST使用) . 规范要求浏览器“预检”请求,使用HTTP OPTIONS请求标头从服务器请求支持的方法,然后,在服务器“批准”时,使用实际的HTTP请求方法发送实际请求 . 服务器还可以通知客户端是否应该随请求一起发送“凭证”(包括Cookie和HTTP身份验证数据) .

    很难提供适用于所有WWW服务器的通用解决方案,因为设置将根据您打算支持的服务器本身和HTTP谓词而有所不同 . 我鼓励你克服这篇优秀的文章(http://www.html5rocks.com/en/tutorials/cors/),它有关于服务器需要发送的确切 Headers 的更多细节 .

  • 60

    对于IIS MVC 5 / Angular CLI(是的,我很清楚你的问题是使用Angular JS)项目使用API我做了以下事情:

    web.config<system.webServer> 节点下

    <staticContent>
          <remove fileExtension=".woff2" />
          <mimeMap fileExtension=".woff2" mimeType="font/woff2" />
        </staticContent>
        <httpProtocol>
          <customHeaders>
            <clear />
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Headers" value="Content-Type, atv2" />
            <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS"/>
          </customHeaders>
        </httpProtocol>
    

    global.asax.cs

    protected void Application_BeginRequest() {
      if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OrdinalIgnoreCase) && Request.HttpMethod == "OPTIONS") {
        Response.Flush();
        Response.End();
      }
    }
    

    这应该解决你的MVC和WebAPI的问题,而不必做所有其他运行 . 然后我在Angular CLI项目中创建了一个HttpInterceptor,它自动添加到相关的头信息中 . 希望这可以帮助某人在类似的情况下 .

  • 0

    不知怎的,我通过改变来修复它

    <add name="Access-Control-Allow-Headers" 
         value="Origin, X-Requested-With, Content-Type, Accept, Authorization" 
         />
    

    <add name="Access-Control-Allow-Headers" 
         value="Origin, Content-Type, Accept, Authorization" 
         />
    
  • 218

    我放弃了试图解决这个问题 .

    我的IIS web.config中有相关的“ Access-Control-Allow-Methods ”,我尝试将配置设置添加到我的Angular代码中,但是在烧了几个小时试图让Chrome调用跨域JSON Web服务后,我惨遭失望 .

    最后,我添加了一个愚蠢的ASP.Net处理程序网页,得到它来调用我的JSON Web服务,并返回结果 . 它在2分钟内启动并运行 .

    这是我使用的代码:

    public class LoadJSONData : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
    
            string URL = "......";
    
            using (var client = new HttpClient())
            {
                // New code:
                client.BaseAddress = new Uri(URL);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Add("Authorization", "Basic AUTHORIZATION_STRING");
    
                HttpResponseMessage response = client.GetAsync(URL).Result;
                if (response.IsSuccessStatusCode)
                {
                    var content = response.Content.ReadAsStringAsync().Result;
                    context.Response.Write("Success: " + content);
                }
                else
                {
                    context.Response.Write(response.StatusCode + " : Message - " + response.ReasonPhrase);
                }
            }
        }
    
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
    

    在我的Angular控制器中......

    $http.get("/Handlers/LoadJSONData.ashx")
       .success(function (data) {
          ....
       });
    

    我确信有一种更简单/更通用的做法,但生活太短暂......

    这对我有用,我现在可以继续正常工作!

  • 10

    同一份文件说

    与简单请求(如上所述)不同,“预检”请求首先将HTTP OPTIONS请求头发送到另一域上的资源,以便确定实际请求是否可安全发送 . 跨站点请求这样预检,因为它们可能会对用户数据产生影响 . 特别是,如果出现以下情况,请求会被预检:

    它使用GET或POST以外的方法 . 此外,如果POST用于发送具有除application / x-www-form-urlencoded,multipart / form-data或text / plain之外的Content-Type的请求数据,例如,如果POST请求使用application / xml或text / xml将XML有效负载发送到服务器,则该请求将被预检 . 它在请求中设置自定义标头(例如,请求使用标头,如X-PINGOTHER)

    当原始请求是Get而没有自定义标头时,浏览器不应该发出它现在所做的选项请求 . 问题是它生成一个 Headers X-Requested-With强制选项请求 . 有关如何删除此 Headers ,请参阅https://github.com/angular/angular.js/pull/1454

  • 34

    这是我在ASP.NET上修复此问题的方法

    • 首先,你应该添加nuget包 Microsoft.AspNet.WebApi.Cors

    • 然后修改文件App_Start \ WebApiConfig.cs

    public static class WebApiConfig    
    {
       public static void Register(HttpConfiguration config)
       {
          config.EnableCors();
    
          ...
       }    
    }
    
    • 在控制器类上添加此属性
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class MyController : ApiController
    {  
        [AcceptVerbs("POST")]
        public IHttpActionResult Post([FromBody]YourDataType data)
        {
             ...
             return Ok(result);
        }
    }
    
    • 我能够通过这种方式将json发送到动作
    $http({
            method: 'POST',
            data: JSON.stringify(data),
            url: 'actionurl',
            headers: {
                'Content-Type': 'application/json; charset=UTF-8'
            }
        }).then(...)
    

    参考:Enabling Cross-Origin Requests in ASP.NET Web API 2

  • 20

    您的服务必须回答带有以下 Headers 的 OPTIONS 请求:

    Access-Control-Allow-Origin: [the same origin from the request]
    Access-Control-Allow-Methods: GET, POST, PUT
    Access-Control-Allow-Headers: [the same ACCESS-CONTROL-REQUEST-HEADERS from request]
    

    这是一个很好的文档:http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server

  • 65

    在pkozlowski的评论中有完美的描述 . 我有AngularJS 1.2.6和ASP.NET Web Api的工作解决方案,但当我将AngularJS升级到1.3.3时,请求失败 .

    • Web Api服务器的解决方案是在配置方法开始时添加OPTIONS请求的处理(更多信息in this blog post):
    app.Use(async (context, next) =>
    {
        IOwinRequest req = context.Request;
        IOwinResponse res = context.Response;
        if (req.Path.StartsWithSegments(new PathString("/Token")))
        {
            var origin = req.Headers.Get("Origin");
            if (!string.IsNullOrEmpty(origin))
            {
                res.Headers.Set("Access-Control-Allow-Origin", origin);
            }
            if (req.Method == "OPTIONS")
            {
                res.StatusCode = 200;
                res.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Methods", "GET", "POST");
                res.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Headers", "authorization", "content-type");
                return;
            }
        }
        await next();
    });
    
  • 0

    这解决了我的问题:

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

相关问题