c# - 仅在文件上传时出现 Asp.Net Core API CORS 策略错误
问题描述
仅在使用 AspNet Core API 3.1 将文件上传到服务器时出现 CORS 策略阻止错误。以不同的方式将 cors 策略添加到启动并使用自定义中间件并没有解决我的问题。
启动:
// 配置服务
services.AddCors(options =>
{
options.AddPolicy("EnableSVCCors", builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.Build();
});
});
// 配置
app.UseCors("EnableSVCCors");
通过从反应客户端网站调用所有 API 方法都可以正常工作,但是在尝试上传图像时出现以下错误:
从源“ http://172.16.1.35:3000 ”访问“ http://172.16.1.34:1980/api/accounts/uploadAvatar ”的 XMLHttpRequest已被 CORS 策略阻止:否“访问控制允许源” ' 请求的资源上存在标头。
我还尝试如下更改 cors 政策,但不起作用:
services.AddCors(options =>
{
options.AddPolicy("EnableSVCCors", builder =>
{
builder
.WithOrigins("http://172.16.1.35:3000")
.AllowAnyHeader()
.AllowAnyMethod()
.Build();
});
});
注意:使用 PostMan 调用http://172.16.1.34:1980/api/accounts/uploadAvatar并将 base64 字符串作为图像发送工作正常!因此,对要保存图像的文件夹的访问限制没有问题。
我还尝试添加自定义中间件,如下所示,但还没有工作:
public class CorsMiddleWare
{
private readonly RequestDelegate _next;
public CorsMiddleWare(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "http://172.16.1.35:3000");
return _next(httpContext);
}
}
public static class CorsMiddlewareExtensions
{
public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CorsMiddleWare>();
}
}
任何人有任何想法吗?
编辑:控制台中的返回标题如下
请求 URL:http ://172.16.1.34:1980/api/accounts/uploadAvatar 推荐人策略:no-referrer-when-downgrade 日期:2020 年 4 月 14 日星期二 03:50:49 GMT 服务器:Microsoft-IIS/10.0 Transfer-编码:chunked X-Powered-By: ASP.NET Accept: application/json, text/plain, / Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Authorization: Bearer eyJhb... .. 连接:keep-alive 内容长度:22869 内容类型:application/json;charset=UTF-8 主机:172.16.1.34:1980 来源 :http: //172.16.1.35 :3000 参考: http://172.16 .1.35:3000/创建配置文件用户代理:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36 {fileName: "avatar", mediaType: "image/png",...}文件名:“头像”媒体类型:“图像/png”缓冲区:“iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6CAYAAACI7Fo9AAAgAE
解决方案
通过更改对象类型解决的问题是作为图像文件发送到 HttpFile 包含在 MultipartDataMediaFormatter.V2 https://github.com/iLexDev/ASP.NET-WebApi-MultipartDataMediaFormatter
上传视图模型:
public class ProfileAvatarUploadViewModel
{
public HttpFile Image { get; set; }
}
API 控制器:
[HttpPost("UploadAvatar")]
[Authorize(AuthenticationSchemes = "Bearer", Roles = "Manager,Admin,User")]
public async Task<IActionResult> UploadAvatar([FromBody] ProfileAvatarUploadViewModel model)
{
var userId = User.FindFirst(ClaimTypes.Name)?.Value;
if (userId == null || !await _userAccountRepository.IsExists(int.Parse(userId)))
{
return Forbid();
}
var avatarToUpload = new ProfileAvatarUploadModel
{
UserAccountId = int.Parse(userId),
UploadedImage = model.Image
};
var uploadedAvatar = await _profileAvatarRepository.UploadAvatar(avatarToUpload);
return Ok(uploadedAvatar);
}
存储库:
public async Task<ProfileAvatarViewModel> UploadAvatar(ProfileAvatarUploadModel model)
{
var (key, value) = SVCardTools.SaveImage(model.UploadedImage);
if (key.Equals(false))
{
throw new Exception(value);
}
var newAvatar = new ProfileAvatar
{
UserAccountId = model.UserAccountId,
AvatarUrl = value,
IsActive = false,
IsPublic = false
};
_context.Entry(newAvatar).State = EntityState.Added;
await _context.SaveChangesAsync();
return ProfileAvatarViewModel.Set(newAvatar);
}
保存图像功能:
public static KeyValuePair<bool, string> SaveImage(HttpFile file)
{
var bytes = file.Buffer;
try
{
var fileExt = file.MediaType.Split('/')[1];
switch (fileExt.ToLower())
{
case "png":
fileExt = ".png";
break;
case "jpg":
fileExt = ".jpg";
break;
default:
return new KeyValuePair<bool, string>(false, "Message");
}
var sb = new StringBuilder();
sb.Append(DateTime.Now.Ticks);
var saveFilePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot\\avatars",
$"{sb}{fileExt}");
var saveDbPath = $"{sb}{fileExt}";
if (bytes.Length > 0)
{
using (var stream = new FileStream(saveFilePath, FileMode.Create))
{
stream.Write(bytes, 0, bytes.Length);
}
}
return new KeyValuePair<bool, string>(true, saveDbPath);
}
catch (Exception e)
{
var message = e.Message;
return new KeyValuePair<bool, string>(false, message);
}
}
推荐阅读
- ruby - Kqueue dirextended 看什么动作?
- android - 如何编写索引?
- c++ - CMake 声明函数对 ExternalProject_Add 的依赖
- sql - postgres SQL查询中如何实现数学表达式?
- kubernetes - Openshift:pod 之间的可见性
- javascript - 通过单击另一个 div 使 div 消失并出现
- tsql - 如何获取从今天开始的前 52 周
- python - Python socket irc bot - socket.gaierror: [Errno 11001] getaddrinfo failed
- ios - Unity iOS 生成的项目无法加载框架:dylib,找不到图像的原因
- angular - XSLXWriter 和 Angular 5,无法更改 Excel 文件中的标题样式