7

我发现在一个页面上有多个处理程序以及相关的命名约定(即 OnPostXXX)和“asp-post-hanlder”标签助手的示例。但是我怎样才能从 AJAX 调用中调用这些方法之一。

我有一个带有典型 MVC 视图和控制器的较旧示例,但这如何与 Razor 页面一起使用?

例如,如果我使用基本应用程序并将 About.cshtml 页面修改为以下内容:

@page
@model AboutModel
@{
    ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>
<h3>@Model.Message</h3>

    <input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();"  />

@section Scripts {
<script type="text/javascript">
    function ajaxTest() {
        console.log("Entered method");
        $.ajax({
            type: "POST",
            url: '/About', // <-- Where should this point?
            contentType: "application/json; charset=utf-8",
            dataType: "json",
        error: function (xhr, status, errorThrown) {
            var err = "Status: " + status + " " + errorThrown;
            console.log(err);
        }
        }).done(function (data) {
            console.log(data.result);
        })
    }
</script>
}

并在模型页面 About.cshtml.cs

public class AboutModel : PageModel
{
    public string Message { get; set; }

    public void OnGet()
    {
        Message = "Your application description page.";
    }

    public IActionResult OnPost() {
        //throw new Exception("stop");
        return new JsonResult("");
    }
}

OnPost 不是从 Ajax 调用中调用的。

4

8 回答 8

19

Razor Pages 自动生成并验证 Antiforgery 令牌以防止CSRF攻击。由于您没有在 AJAX 回调中发送任何令牌,因此请求失败。

要解决此问题,您必须:

  1. 注册防伪服务
  2. 将令牌添加到您的请求中
  3. 通过添加 a<form>或直接使用@Html.AntiForgeryTokenHtmlHelper将防伪令牌添加到您的页面

1. 注册 Antiforgery-Service 在您的Startup.cs

public void ConfigureServices(IServiceCollection services)
{
  services.AddRazorPages();
  services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
}

2.修改你的AJAX回调

在 AJAX 回调中,我们添加了额外的代码来发送XSRF-TOKEN我们的请求标头。

$.ajax({
    type: "POST",
    url: '/?handler=YOUR_CUSTOM_HANDLER', // Replace YOUR_CUSTOM_HANDLER with your handler.
    contentType: "application/json; charset=utf-8",

    beforeSend: function (xhr) {
      xhr.setRequestHeader("XSRF-TOKEN",
        $('input:hidden[name="__RequestVerificationToken"]').val());
    },

    dataType: "json"
}).done(function (data) {
  console.log(data.result);
})

3. 将防伪令牌添加到您的页面

您可以通过添加<form>

<form method="post">
    <input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
</form>

或通过使用@Html.AntiForgeryToken

@Html.AntiForgeryToken()
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />

在这两种情况下,加载页面后,Razor Pages 都会自动添加一个隐藏的输入字段,其中包含防伪令牌:

<input name="__RequestVerificationToken" type="hidden" value="THE_TOKEN_VALUE" />
于 2017-09-26T01:44:41.870 回答
1

请参阅文档的相关部分 https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=visual-studio

URL 路径与页面的关联由页面在文件系统中的位置决定。下表显示了 Razor 页面路径和匹配的 URL

/Pages/Index.cshtml 映射到 / 或 /Index

/Pages/Contact.cshtml 映射到 /Contact

于 2017-09-25T19:47:51.903 回答
1

一切正常,但必须进行一些更改:

1)打开Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
            services.AddMvc();
        }

2)打开 HomeController.cs:

[ValidateAntiForgeryToken]
        public IActionResult OnPost()
        {
            return new JsonResult("Hello Response Back");
        }

3)打开About.cshtml:

@{
    ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>

<p>Use this area to provide additional information.</p>
<form method="post">
    <input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>

<script type="text/javascript">
    function ajaxTest() {
        $.ajax({
            type: "POST",
            url: 'onPost',
            contentType: "application/json; charset=utf-8",
            beforeSend: function (xhr) {
                xhr.setRequestHeader("XSRF-TOKEN",
                    $('input:hidden[name="__RequestVerificationToken"]').val());
            },
            dataType: "json"
        }).done(function (data) {
            console.log(data.result);
        })
    }
</script>

需要注意的是,“onPost”是在控制器内部添加的,所以在 AJAX 中应该指明正确的“url”。然后:

url: 'onPost',
于 2017-11-28T10:22:48.433 回答
1

在查看了上面的答案后,我使用 Visual Studio 2017 Preview 2 让 JSON ajax 与 .NET Core 2.1 Razor 页面一起工作:

启动.cs

services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");

PostJson.cshtml

@page
@model myProj.Pages.PostJsonModel
@{
    ViewData["Title"] = "PostJson";
}

<input type="button" value="Post Json" class="btn btn-default" onclick="postJson();" />

<script>
    function ajaxRazorPostJson(o) {
        return $.ajax({
            type: "POST",
            data: JSON.stringify(o),
            url: 'postJson',
            contentType: "application/json; charset=utf-8",
            beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); },
            dataType: "json"
        });
    }

    function postJson() {
        ajaxRazorPostJson({ reqKey: "reqVal" }).done(data => alert(data));
    }
</script>

PostJson.cshtml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json.Linq;    

namespace myProj.Pages
{
    public class PostJsonModel : PageModel
    {
        public IActionResult OnPost([FromBody] JObject jobject)
        {
            // request buffer in jobject
            return new ContentResult { Content = "{ \"resKey\": \"resVal\" }", ContentType = "application/json" };
            // or ie return new JsonResult(obj);
        }
    }
}

浏览器

http://localhost:44322/postJson

于 2018-06-01T00:14:23.333 回答
0

接受的解决方案在本地开发机器上工作,但失败然后部署在 Nginx 反向代理后面的 Debian 服务器中(未找到 404 错误)。

这是一个有效负载数据的工作示例:

<script type="text/javascript">
    $('#btnPost').on('click', function () {

        var payloadData; /*asign payload data here */

        $.post({              /* method name in code behind, and full path to my view*/
            url: '@Url.Action("OnPostAsync", "/Turtas/Inventorius/InventoriausValdymas")', 
            beforeSend: function (xhr) {
                xhr.setRequestHeader("XSRF-TOKEN",
                    $('input:hidden[name="__RequestVerificationToken"]').val());
            },
            data: JSON.stringify({ payloadData }),
            contentType: "application/json; charset=utf-8",
            dataType: "json"
        })
    })
</script>

与 2017 年相比;.Net Core 2.2 Razor 页面;jQuery 3.3.1

于 2019-02-06T14:03:13.887 回答
0

以下内容适用于使用headers设置的 ASP.NET Core MVC 3.1:

$.ajax({
    type: "POST",
    url: '/Controller/Action', 
    data: {
        id: 'value'
    },
    headers: {
        RequestVerificationToken:
            $('input:hidden[name="__RequestVerificationToken"]').val()
    },
    error: function (xhr, status, errorThrown) {
        var err = "Error: " + status + " " + errorThrown;
        console.log(err);
    }
}).done(function (data) {
    console.log(data.result);
});

在控制器方法中包含ValidateAntiForgeryToken属性:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<JsonResult> Action(string id)
    {
        var result = $"You sent '{id}'";
        return Json(new { id, result });
    }
于 2020-02-29T22:23:55.567 回答
0

我为后代添加这个。在解决同样的问题时,我发现了可以添加到 Startup.cs 中的以下代码:

services.AddRazorPages().AddRazorPagesOptions(options =>
{
    options.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
});

不再需要防伪令牌。

于 2021-11-10T22:52:43.460 回答
-1

答案对我有用。我只会补充说,如果我们在页面上有自定义方法,例如:

   public IActionResult OnPostFilter1()
    {
        return new JsonResult("Hello Response Back");
    }

然后我们应该在 url 中指定处理程序名称:

url: 'OnPost?handler=filter1',
于 2018-03-10T21:24:56.090 回答