【问题标题】:Calling a secured ASP.NET Core 5 Web API results in HTTP 406 - Not Acceptable error调用安全的 ASP.NET Core 5 Web API 会导致 HTTP 406 - Not Acceptable 错误
【发布时间】:2021-11-14 02:37:27
【问题描述】:

我有一个 ASP.NET Core 5 Web API,它为两个应用程序提供一些数据。一个是 Angular SPA,这个设置工作得很好 - Angular 应用程序获取它的数据,可以显示它,一切看起来都很好。

我的另一个应用是带有 Razor 页面的 ASP.NET Core 5 MVC 应用。我可以使用 Microsoft 身份系统和 OpenID Connect 登录 - 用户被正确发现并且一切看起来都很好 - 但是当我进行 API 调用时,我得到了一个“HTTP 406 - Not Acceptable”错误。

根据我的研究,这似乎很可能是由于 API 不匹配而没有提供调用者可以处理的数据类型。这让我很困惑,因为我的 API 提供了 JSON(并且使用 Angular 应用程序,它工作得很好),而我的 MVC 应用程序也需要 JSON - 所以我一直在摸不着头脑,想知道我可能错过了什么...... ..

我的 Web API 是这样设置的(启动/配置服务):

services.AddAuthentication(x => {
                                    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                                    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                                })
        .AddJwtBearer(x => {
                                x.RequireHttpsMetadata = false;
                                x.SaveToken = true;
                                x.TokenValidationParameters = new TokenValidationParameters
                                         {
                                               ValidateIssuerSigningKey = false,
                                               ValidateIssuer = false,
                                               ValidateAudience = true,
                                               ValidAudience = Configuration.GetValue<string>("AzureAd:Audience"),
                                               ValidateLifetime = true,
                                               ClockSkew = TimeSpan.Zero
                                         };
                           });

services.AddMvc();
services.AddControllers().AddJsonOptions(options => { 
                                                        options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
                                                    });

及其控制器都在控制器级别指定[Produces("application/json")]注解:

[Route("api/data")]
[ApiController]
[Produces("application/json")]
[Authorize]
public class DataController : MyBaseController
{
    // code for the controller

    // this is one of the action methods
    [HttpGet]
    [Route("review")]
    public IActionResult GetListForReview()
    {
        _logger.LogInformation("Get Review List");

        IEnumerable<OverviewListDto> data = _repository.GetOverviewListForReview();
        return Ok(data);
    }   
}

所以我认为这是我能做的所有事情,以确保我发送回正确的 JSON。

我的 MVC 应用正在使用 .NET Core 5 HttpClient,我这样设置:

_httpClient = new HttpClient();
_httpClient.BaseAddress = new Uri(_apiConfig.BaseUrl);

_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _apiConfig.AccessToken);

所以我有点期待获取和解析 JSON 应该可以正常工作 - 还是我弄错了?还有什么可能导致这样的“HTTP 406 - Not Acceptable”错误?我还能检查/确保什么?

【问题讨论】:

  • 您能分享您尝试访问的端点的签名吗?是否不止一个端点?
  • @BenMatthews:这只是一个简单的GET 请求(GET https://myserver.abc/myapi/ctrl/getdata - 没有参数 - 只是一个简单的调用)。它发生在多个端点上,因此看起来不像是单个端点/ URL 的特定问题。
  • 这很奇怪...你能检查一下流量,看看请求中的接受标头是什么吗?
  • 请您也展示一下您的 API 操作吗?
  • @Serge:添加了一种方法作为示例——它们看起来都非常相似,基本上都将实际工作委托给存储库类,它只返回一个符合任何标准的 DTO 列表申请任何给定的电话

标签: c# asp.net-core-mvc asp.net-core-webapi asp.net-core-5.0


【解决方案1】:

当您发出请求时,应在 Content-Type 标头中设置预期的响应类型。

你可以这样做(来源:https://stackoverflow.com/a/10679340/8404545

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://example.com/");
client.DefaultRequestHeaders
      .Accept
      .Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT 
header

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, 
"relativeAddress");
request.Content = new StringContent("{\"name\":\"John Doe\",\"age\":33}",
                                    Encoding.UTF8, 
                                    "application/json");//CONTENT-TYPE header

client.SendAsync(request)
      .ContinueWith(responseTask =>
      {
          Console.WriteLine("Response: {0}", responseTask.Result);
      });

【讨论】:

  • 那么您是说获取对象列表,使用return Ok(data); 返回它们,并在控制器类上添加[Produces("application/json")] 注释是不够的/不是正确的方法吗?这是在 Web API 中的 服务器端 - 您的代码似乎与客户端(MVC 应用程序)有关,我不想从那里发送任何数据....(只是阅读它)
  • @marc_s 您对它所做的事情的看法是正确的,但您得到的错误是客户说它返回的数据与请求的格式不匹配。此客户端代码指定它应该返回 Json。此外,在服务器而不是 Ok(Data) 上,更明确的 Json(Data) 可能会有所帮助。
【解决方案2】:

406 与授权 JWT 无关。这都是关于 http 响应的。

您是否尝试过使用邮递员?如果成功,您可以检查 Postman 用于获取数据的标头。

我正在为 http get 请求使用这样的代码。它工作 100%

using (var client = new HttpClient())
{
    var baseAddress = "http://localhost:44365";

    var api = "/api/data/review";
    client.BaseAddress = new Uri(baseAddress);
    var contentType = new MediaTypeWithQualityHeaderValue("application/json");
    client.DefaultRequestHeaders.Accept.Add(contentType);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var response = await client.GetAsync(api)
      //var statusCode = response.StatusCode.ToString();
    if (response.IsSuccessStatusCode)
    {
        var stringData = await response.Content.ReadAsStringAsync();
        var result = JsonConvert.DeserializeObject<object>(stringData);
    }
}

我在您的代码中看不到 var response = await client.GetAsync(api)。因此,请确保您有正确的 api 路径,您可以调用不同的操作然后您想要。并检查您需要的 http 或 https。

【讨论】:

    猜你喜欢
    • 2019-12-15
    • 2016-12-01
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    • 2014-02-21
    • 2016-02-21
    • 2014-11-12
    • 1970-01-01
    相关资源
    最近更新 更多