ASP.NET Core Razor Pages中Ajax POST到同页面事件处理器报400错误
问题描述
使用.NET 8和VS2022开发ASP.NET Core Razor Pages,为避免控制器暴露给公众,所有POST请求均指向同页面的事件处理器(如www.mywebsite.com/index调用该页的ASP.NET Core事件处理器)。遇到以下问题:
- 场景1:Ajax POST上传文件时,携带防伪令牌调用控制器可成功,但调用同页面事件处理器失败;
- 场景2:上传文件到index页时触发400错误,尝试过
IActionResult返回值及ImageUpload类(代码已注释),均得到相同结果。
后端代码
//public async Task<IActionResult> OnPostAsync(ImageUpload imageUpload) public async Task OnPostAsync() { var file = Request.Form.Files[0]; var fileName = Path.GetFileName(file.FileName); var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/uploads", fileName); using (var fileStream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(fileStream); } //return Content($"File '{fileName}' uploaded successfully."); }
前端代码(已尝试JSON.stringify但无效)
$('#fileInput').change(function () { var token = $('#__RequestVerificationToken').val(); var file = this.files[0]; if (file) { var reader = new FileReader(); var formData = new FormData(); formData.append('file', file); reader.onload = function (e) { $('#previewImage').attr('src', e.target.result).show(); var formData = new FormData(); formData.append('file', file); var formData2 = JSON.stringify(formData); $.ajax({ type: "POST", url: "",//this enables it to post to the root contentType: "application/json", processData: false, data: formData2, headers: { RequestVerificationToken: token }, success: function (response) { console.log('File uploaded successfully'); }, error: function (xhr, status, error) { console.error('Error uploading file:', error); } }); }; } });
HTML代码
<form> @Html.AntiForgeryToken() <p> <input type="file" id="fileInput" accept="image/*"> <br><br> <img src="" id="previewImage" style="max-width: 300px; max-height: 300px; display: none;"> </p> </form>
解决方案
1. 修复前端FormData与请求格式问题
400错误的核心原因是文件上传错误使用了JSON格式传递数据,Razor Pages页面处理器无法解析JSON格式的文件流,必须使用multipart/form-data格式。
修改后的前端代码:
$('#fileInput').change(function () { var token = $('#__RequestVerificationToken').val(); var file = this.files[0]; if (file) { var reader = new FileReader(); reader.onload = function (e) { $('#previewImage').attr('src', e.target.result).show(); // 直接构建FormData,包含文件和防伪令牌 var formData = new FormData(); formData.append('file', file); formData.append('__RequestVerificationToken', token); $.ajax({ type: "POST", url: "", // 指向当前页面 processData: false, // 禁止jQuery自动处理FormData contentType: false, // 让浏览器自动设置multipart/form-data及boundary data: formData, success: function (response) { console.log('File uploaded successfully'); }, error: function (xhr, status, error) { console.error('Error uploading file:', error); } }); }; // 必须调用readAsDataURL才会触发reader.onload reader.readAsDataURL(file); } });
2. 优化后端代码(可选但更规范)
恢复使用模型绑定,并确保上传目录存在:
首先定义ImageUpload类:
public class ImageUpload { public IFormFile File { get; set; } }
修改后端方法:
public async Task<IActionResult> OnPostAsync([FromForm] ImageUpload imageUpload) { // 校验文件是否存在 if (imageUpload.File == null || imageUpload.File.Length == 0) { return BadRequest("未选择上传文件"); } var uploadsDir = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/uploads"); // 确保上传目录存在,避免文件写入失败 if (!Directory.Exists(uploadsDir)) { Directory.CreateDirectory(uploadsDir); } var fileName = Path.GetFileName(imageUpload.File.FileName); var filePath = Path.Combine(uploadsDir, fileName); using (var fileStream = new FileStream(filePath, FileMode.Create)) { await imageUpload.File.CopyToAsync(fileStream); } return Content($"文件 '{fileName}' 上传成功"); }
3. 防伪令牌验证确认
Razor Pages默认自动验证POST请求的防伪令牌,只需确保:
- 令牌名称为
__RequestVerificationToken(与@Html.AntiForgeryToken()生成的一致); - 令牌通过FormData传递(而非请求头,避免配置冲突)。
内容的提问来源于stack exchange,提问作者Adesuwa
相关产品推荐
相关产品推荐

