Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
CORS-Ajax错误函数将返回401的API请求的错误代码报告为0 背景_Ajax_Jquery_Cors - Fatal编程技术网

CORS-Ajax错误函数将返回401的API请求的错误代码报告为0 背景

CORS-Ajax错误函数将返回401的API请求的错误代码报告为0 背景,ajax,jquery,cors,Ajax,Jquery,Cors,当身份验证(JWT)成功时,我让COR在本地开发环境中工作。我让客户端页面运行localhost并调用api.mycompany.com获取数据。 我的api项目检查有效的JWT,如果通过,则返回内容。我花了一段时间才来到这里,但一切都很好 如果我没有发送有效的JWT,api将正确响应401(在Fiddler中选中),但客户端上的错误函数回调将报告错误代码0和状态“error” 我希望ajax回调函数检查错误的状态代码,如果是401,则检查标题中名为location的标题(其中将包含认证服务的u

当身份验证(JWT)成功时,我让COR在本地开发环境中工作。我让客户端页面运行localhost并调用api.mycompany.com获取数据。 我的api项目检查有效的JWT,如果通过,则返回内容。我花了一段时间才来到这里,但一切都很好

如果我没有发送有效的JWT,api将正确响应401(在Fiddler中选中),但客户端上的错误函数回调将报告错误代码0和状态“error”

我希望ajax回调函数检查错误的状态代码,如果是401,则检查标题中名为location的标题(其中将包含认证服务的uri)

安装程序
  • (API项目)在本地IIS Express上运行MVC4项目的Visual Studio 2012实例

    • 本地主机文件将127.0.0.1映射到api.mycompany.com
    • 将Project->Properties->Web设置为IIS Express
      • 使用本地IIS Express(选中)
      • 项目Url:
        http://localhost:8080
      • 创建虚拟目录
      • 覆盖应用程序根URL(已选中)
      • 覆盖应用程序根URL:
        http://api.mycompany.com:8080
    • 在“站点”下的applicationhost.config中:

      <site name="StuffManagerAPI" id="1">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
          <virtualDirectory path="/" physicalPath="C:\Users\me\Documents\Visual Studio 2012\Projects\StuffManagerAPI\StuffManagerAPI" />
        </application>
        <bindings>
          <binding protocol="http" bindingInformation="*:8080:localhost" />
          <binding protocol="http" bindingInformation="*:8080:api.mycompany.com" />
        </bindings>
      </site>
      
      物料控制器

      using System.Collections.Generic;
      using System.Linq;
      using System.Net;
      using System.Net.Http;
      using System.Threading.Tasks;
      
      namespace StuffManagerAPI.Handlers
      {
      public class AuthorizationHeaderHandler : DelegatingHandler
      {
          private const string KEY = "theKey";
      
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
          {
              var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>();
      
              const string identityProviderUri = "https://idp.mycompany.com";
      
              IEnumerable<string> apiKeyHeaderValues = null;
              if (request.Headers.TryGetValues("Authorization", out apiKeyHeaderValues))
              {
                  var apiKeyHeaderValue = apiKeyHeaderValues.First();
                  var token = apiKeyHeaderValue.Split(' ').LastOrDefault();
                  var tokenProcessor = new JasonWebTokenDecryptor.JasonWebToken(token, KEY);
      
                  if (tokenProcessor.IsValid)
                  {
                      base.SendAsync(request, cancellationToken).ContinueWith(t => taskCompletionSource.SetResult(t.Result));
                  }
                  else
                  {
                      var response = FailedResponseWithAddressToIdentityProvider(identityProviderUri);
                      taskCompletionSource.SetResult(response);
                  }
      
              }
              else
              {
                  if(request.Method.Method != "OPTIONS")
                  {
                      //No Authorization Header therefore needs to redirect
                      var response = FailedResponseWithAddressToIdentityProvider(identityProviderUri);
                      taskCompletionSource.SetResult(response);
                  }
                  else
                  {
                      base.SendAsync(request, cancellationToken).ContinueWith(t => taskCompletionSource.SetResult(t.Result));
                  }
              }
      
              return taskCompletionSource.Task;
          }
      
          private static HttpResponseMessage FailedResponseWithAddressToIdentityProvider(string identityProviderUri)
          {
              // Create the response.
              var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
              response.Headers.Add("Location", identityProviderUri);
              return response;
          }
      }
      }
      
      using System.Collections.Generic;
      using System.Linq;
      using System.Net;
      using System.Web.Http;
      using StuffManagerAPI.Attributes;
      using StuffManagerAPI.Models;
      
      namespace StuffManagerAPI.Controllers
      {
      [HttpHeader("Access-Control-Allow-Origin", "*")]
      [HttpHeader("Access-Control-Allow-Methods", "OPTIONS, HEAD, GET, POST, PUT, DELETE")]
      [HttpHeader("Access-Control-Allow-Headers", "Authorization")]
      [HttpHeader("Access-Control-Expose-Headers", "Location")]
      public class StuffController : ApiController
      {
          private readonly Stuff[] _stuff = new[]
              {
                  new Stuff
                      {
                          Id = "123456",
                          SerialNumber = "112233",
                          Description = "Cool Item"
                      },
                  new Stuff
                      {
                          Id = "456789",
                          SerialNumber = "445566",
                          Description = "Another Cool Item"
                      }
              };
      
          public Stuff Get(string id)
          {
              var item = _stuff.FirstOrDefault(p => p.Id == id);
              if (item == null)
              {
                  throw new HttpResponseException(HttpStatusCode.NotFound);
              }
      
              return item;
          }
      
          public IEnumerable<Stuff> GetAll()
          {
              return _stuff;
          }
      
          public void Options()
          {
             // nothing....
          }
      
      }
      }
      
      使用System.Collections.Generic;
      使用System.Linq;
      Net系统;
      使用System.Web.Http;
      使用StuffManagerAPI.Attributes;
      使用StuffManagerAPI.Models;
      命名空间StuffManagerAPI.Controllers
      {
      [HttpHeader(“访问控制允许来源”,“*”)]
      [HttpHeader(“访问控制允许方法”、“选项、HEAD、GET、POST、PUT、DELETE”)]
      [HttpHeader(“访问控制允许标头”、“授权”)]
      [HttpHeader(“访问控制公开头”、“位置”)]
      公共类StuffController:ApicController
      {
      私有只读内容[]_Stuff=new[]
      {
      新东西
      {
      Id=“123456”,
      SerialNumber=“112233”,
      Description=“酷项”
      },
      新东西
      {
      Id=“456789”,
      SerialNumber=“445566”,
      Description=“另一款酷款”
      }
      };
      公共内容获取(字符串id)
      {
      var item=\u stuff.FirstOrDefault(p=>p.Id==Id);
      如果(项==null)
      {
      抛出新的HttpResponseException(HttpStatusCode.NotFound);
      }
      退货项目;
      }
      公共IEnumerable GetAll()
      {
      退货;
      }
      公开作废期权()
      {
      //没什么。。。。
      }
      }
      }
      
      客户项目 main.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <title>ASP.NET Web API</title>
          <link href="../Content/Site.css" rel="stylesheet" />
          <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.js"></script>
      
          <script type="text/javascript">
              var baseUrl = "http://api.mycompany.com:8080/api/";
              $.support.cors = true;
      
              $(document).ready(
                  getListofStuff()
              );
      
              function setHeader(xhr) {
                  xhr.setRequestHeader('authorization', 'Bearer blah.blah.blah');
              }
      
              function getListofStuff() {
                  var apiUrl = baseUrl + "stuff/";
      
                  $.ajax({
                      url: apiUrl,
                      type: 'GET',
                      dataType: 'json',
                      crossDomain: true,
                      success: receivedListOfStuff,
                      error: receiveError,
                      beforeSend: setHeader,
                      statusCode: {
                          0: function() {
                              alert('got 0');
                          },
                          401: function () {
                              alert('finally got a 401');
                          }
                      }
                  });
              }
      
              function getIndividualPieceOfStuff(id) {
                  var apiUrl = baseUrl + "stuff/" + id;
      
                  $.ajax({
                      url: apiUrl,
                      type: 'GET',
                      dataType: 'json',
                      crossDomain: true,
                      success: receivedIndividualStuffItem,
                      error: receiveError,
                      beforeSend: setHeader
                  });
              }
      
              function receivedListOfStuff(data) {
                  $.each(data, function (key, val) {
      
                      var listItem = $('<li/>').text(val.Description);
                      listItem.data("content", { id: val.Id});
                      $(".myStuff").prepend(listItem);
                  });
      
                  $(".myStuff li").click(function () {
                      getIndividualPieceOfStuff($(this).data("content").id);
                  });
              }
      
              function receivedIndividualStuffItem(data) {
                  $("#stuffDetails #id").val(data.Id);
                  $("#stuffDetails #serialNumber").val(data.SerialNumber);
                  $("#stuffDetails #description").val(data.Description);
              }
      
              function receiveError(xhr, textStatus, errorThrown) {
                  var x = xhr.getResponseHeader("Location");
                  var z = xhr.responseText;
      
                  if (xhr.status == 401){
                      alert('finally got a 401');
                     }
      
                  alert('Error AJAX');
              }
          </script>
      
      </head>
      <body>
      .
      .
      .
      .
      </body>
      </html>
      
      
      水果刀
      var baseUrl=”http://api.mycompany.com:8080/api/";
      $.support.cors=true;
      $(文件)。准备好了吗(
      getListofStuff()
      );
      函数setHeader(xhr){
      setRequestHeader('authorization','beareh.blah.blah');
      }
      函数getListofStuff(){
      var apiUrl=baseUrl+“stuff/”;
      $.ajax({
      url:apiUrl,
      键入:“GET”,
      数据类型:“json”,
      跨域:是的,
      成功:已收到Istofstuff,
      错误:receiveError,
      发送前:setHeader,
      状态代码:{
      0:函数(){
      警报('got0');
      },
      401:函数(){
      警惕(“终于拿到了401”);
      }
      }
      });
      }
      函数getIndividualPieceOfStuff(id){
      var apiUrl=baseUrl+“stuff/”+id;
      $.ajax({
      url:apiUrl,
      键入:“GET”,
      数据类型:“json”,
      跨域:是的,
      成功:接受分个人的训练,
      错误:receiveError,
      发送前:setHeader
      });
      }
      函数receivedListOfStuff(数据){
      $。每个(数据、函数(键、值){
      var listItem=$(“
    • ”).text(val.Description); 数据(“内容”{id:val.id}); $(“.myStuff”).prepend(列表项); }); $(“.myStuff li”)。单击(函数(){ getIndividualPieceofStuf($(this).data(“content”).id); }); } 函数receivedIndividualStuffItem(数据){ $(“#stuffDetails#id”).val(data.id); $(“#stuffDetails#serialNumber”).val(data.serialNumber); $(“#stuffDetails#description”).val(data.description); } 函数receiveError(xhr、textStatus、ErrorSwitch){ var x=xhr.getResponseHeader(“位置”); var z=xhr.responseText; 如果(xhr.status==401){ 警惕(“终于拿到了401”); } 警报('Error AJAX'); } . . . .
    • 而是直接在ajax上检查状态代码,您是否可以使用此代码在onComplete上检查

      > $.ajaxSetup({
      >     error: function (x) {     
      >         if (x.status == 401) {
      >             alert("401");
      >         }
      >     } });
      

      我终于明白了。在授权标头处理程序中,当tokenProcessor.IsValid为false时,我跳转到FailedResponseWithAddressToIdentityProvider,然后立即设置结果并将任务标记为完成。因此,我从不访问Stuff Controller并添加访问控制标题:

      if (tokenProcessor.IsValid)
      {
          base.SendAsync(request, cancellationToken).ContinueWith(t => taskCompletionSource.SetResult(t.Result));
      }
      else
      {
          var response = FailedResponseWithAddressToIdentityProvider(identityProviderUri);
                  taskCompletionSource.SetResult(response);
      }
      .
      .
      .
      private static HttpResponseMessage FailedResponseWithAddressToIdentityProvider(string identityProviderUri)
      {
          // Create the response.
          var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
          response.Headers.Add("Location", identityProviderUri);
          return response;
      }
      
      }

      也许有更好的方法可以做到这一点,但我只是在FailedResponseWithAddressToIdentityProvider方法中将标题添加到我的响应中,浏览器最终在Chrome、Firefox和IE8中看到401。变化如下:

      private static HttpResponseMessage FailedResponseWithAddressToIdentityProvider(string identityProviderUri)
      {
          // Create the response.
          var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
          response.Headers.Add("Location", identityProviderUri);
          response.Headers.Add("Access-Control-Allow-Origin", "*");
          response.Headers.Add("Access-Control-Allow-Methods", "OPTIONS, HEAD, GET, POST, PUT, DELETE");
          response.Headers.Add("Access-Control-Allow-Headers", "Authorization");
          response.Headers.Add("Access-Control-Expose-Headers", "Location");
          return response;
      }
      

      我想我也应该在其他浏览器中测试…Firefox返回0,IE 8得到401。OddI对IE8的反应感到惊讶。但一般来说,大多数浏览器给用户提供的信息很少