【问题标题】:Why is this basic ajax call giving me a 400 and not firing to the controller?为什么这个基本的 ajax 调用给了我 400 而没有向控制器触发?
【发布时间】:2018-12-10 21:44:00
【问题描述】:

这只是我最新的 dot net core 2 web 应用程序中的一个问题,它在以前的 dot net 应用程序中运行没有问题。

我有一个自定义 javascript 文件,其中包含指向我的网站托管的各种服务器的路径(主要是开发、测试、实时)。

我的 ajax 调用如下所示:

var gameid = '@Html.Raw(Model.Id)';
    $.ajax({
        type: 'GET',
        url: url() + "UserGames/HasGame?id=" +gameid,
        cache: false,
        success: function (data) {
            console.log(data);
        },
        error: function (req, status, err) {
            console.log('Something went wrong', status, err);
        }
    });

有问题的 url() 只是在测试时查看我的本地服务器(*请注意,此端口已被编辑,是正确的):

function url() {
return "https://localhost:4432/";
}

错误没有触发,因为它甚至没有到达正在使用的控制器功能。

我非常困惑为什么这不起作用,我可以理解如果我得到某种错误返回,但我在我的所有应用程序中都使用了 ajax 调用,并且在使用核心 2 之前根本没有遇到这个问题.

是否有任何改变可能会影响您使用 ajax 调用的方式?

试图触发的方法,但我提到过,它没有击中控制器(注意:该方法中确实有代码,它只是一开始就没有击中控制器)

[HttpGet]
[ValidateAntiForgeryToken]
public async Task<IActionResult> HasGame(int id)
{
    //stuff in here
}

【问题讨论】:

  • 你有没有用 [HttpGet] 注解装饰 HasGame 方法?
  • 您要分享操作方法吗?同时你可以使用 POST。
  • Http status 400 = Bad Request。找到了控制器,但传入的参数无效。您正在考虑未找到的 404。因此,要么您的问题列出了错误的状态代码要么您正在寻找错误的树(服务器代码因其他原因而失败)。
  • 您能否进一步解释一下,我已经发布了所有相关代码,我在控制器上放了一个断点,但它似乎没有命中它。我明白你在说什么,如果我遗漏了一些明显的愚蠢的东西,我不会感到惊讶,但我似乎看不到它。
  • ValidateAntiForgeryToken 可能是问题所在,因为 HttpGet 通常不支持此功能。该属性用于修饰动词,如 Put/Delete/Post 等。

标签: ajax asp.net-mvc asp.net-core-2.0


【解决方案1】:

您收到 400 (Bad Request) 响应,因为框架期望 RequestVerificationToken 作为请求的一部分。框架使用它来防止可能的 CSRF 攻击。如果您的请求没有此信息,框架将返回 400 错误请求。您当前的代码未发送。

您可以通过显式发送 RequestVerificationToken 来修复它

表单标签助手自动创建一个名称属性值为__RequestVerificationToken 的隐藏输入,并将标记存储为隐藏输入的值。

var token = $("[name='__RequestVerificationToken']").val();
var gameid = '@Html.Raw(Model.Id)';
$.ajax({
    type: 'GET',
    url: url() + "UserGames/HasGame?id=" +gameid,
    headers:{ "RequestVerificationToken": token },
    success: function (data) {
        console.log(data);
    },
    error: function (req, status, err) {
        console.log('Something went wrong', status, err);
    }
});

在上面的示例中,我们使用一些 jQuery 代码来获取名称为 __RequestVerificationToken 的输入元素并读取它的值。更强大的方法是将IAntiforgery 实现注入视图并使用GetAndStoreTokens 方法。

我们将向视图注入IHttpContextAccessor。因此,请确保它与 DI 正确连接。将此行添加到您的 Startup 类的 ConfigureServices 方法中。

services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();

现在在您看来,您可以注入IHttpContextAccessorIAntiforgery,然后调用GetAndStoreTokens 来获取令牌。在这里,我将其包装成一个辅助函数。

@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContext
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(HttpContext.HttpContext).RequestToken;
    }
}

现在稍后在我的 js 中,我可以在我的 javascript 代码中调用此方法,而不是使用 jQuery 来获取输入值。

var token = "@GetAntiXsrfRequestToken()";
var gameid = '@Html.Raw(Model.Id)';
$.ajax({
    type: 'GET',
    url: url() + "UserGames/HasGame?id=" +gameid,
    headers:{ "RequestVerificationToken": token },
    success: function (data) {
        console.log(data);
    },
    error: function (req, status, err) {
        console.log('Something went wrong', status, err);
    }
});

只需从操作方法中移除[ValidateAntiForgeryToken] 属性装饰,即可排除此检查。

我建议您利用[ValidateAntiForgeryToken] 方法。将令牌作为请求的一部分发送(第一种方法)

【讨论】:

  • 即使添加了令牌,它仍然没有触发控制器动作。我在控制器上的其他操作都没有发送这个(它们是表单提交而不是 ajax 请求)
  • 表单提交将自动发送此令牌,因为它是表单数据的一部分。在您的 ajax 调用中,您没有发送表单数据(序列化表单),而是使用查询字符串执行 GET 请求。
  • 令牌代码发生了什么?您仍然收到 400 响应吗?
  • 是的,即使我从控制器中删除了令牌,我仍然遇到同样的问题,这就是为什么我无法真正找出问题所在
  • 你还有其他中间返回 400 的地方吗?
【解决方案2】:

如果其他人遇到此问题,我设法通过对调用和控制器执行以下操作来解决它:

type: 'GET',
url: '@Url.Action("HasGame", "UserGames")',
data: {id : gameid},

核心 2 中的控制器似乎根本不喜欢你声明 [HttpGet],所以我也删除了它。

感谢您提供的所有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 2021-08-22
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    相关资源
    最近更新 更多