gpt4 book ai didi

ajax - CORS - 对于返回 401 的 API 请求,Ajax 错误函数将错误代码报告为 0

转载 作者:行者123 更新时间:2023-12-03 22:27:48 26 4
gpt4 key购买 nike

背景

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

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

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

设置

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

    • 本地主机文件将 127.0.0.1 映射到 api.mycompany.com
    • 将项目 -> 属性 -> Web 设置为 IIS Express
      • 使用本地 IIS Express(选中)
      • 项目网址: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>
  • (客户端项目)使用 ASP.net 空 Web 应用程序单独的 Visual Studio 实例

    • 将项目 -> 属性 -> Web 设置为 IIS Express
      • 使用本地 IIS Express(选中)
      • 项目网址:http://localhost:22628
      • 已创建虚拟目录
  • 使用 Google Chrome 作为测试客户端

  • 使用Fiddler查看流量

代码

我认为这些应该是我的概念验证中的重要部分。再一次,CORS 预检和数据检索一切正常。这只是未经授权的情况下不起作用。如果您还需要任何其他信息,请告诉我。感谢您的帮助。

API 项目

授权 header 处理程序

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;
}
}
}

东西 Controller

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....
}

}
}

客户项目

ma​​in.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>

最佳答案

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

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 方法中将 header 添加到我的响应中,浏览器最终在 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;
}

关于ajax - CORS - 对于返回 401 的 API 请求,Ajax 错误函数将错误代码报告为 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14268706/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com