仅在文件上传中出现 Asp.Net Core API CORS 策略错误

Posted

技术标签:

【中文标题】仅在文件上传中出现 Asp.Net Core API CORS 策略错误【英文标题】:Asp.Net Core API CORS policy error only in file upload 【发布时间】:2020-07-26 11:36:46 【问题描述】:

仅在使用 AspNet Core API 3.1 将文件上传到服务器时出现 CORS 策略阻止错误。以不同的方式将 cors 策略添加到启动并使用自定义中间件并没有解决我的问题。

启动:

// 配置服务

    services.AddCors(options =>
    
        options.AddPolicy("EnableSVCCors", builder =>
        
            builder
                .AllowAnyOrigin()
                .AllowAnyHeader()
                .AllowAnyMethod()
                .Build();
        );
    );

// 配置

    app.UseCors("EnableSVCCors");

通过从反应客户端网站调用所有 API 方法都可以正常工作,但在尝试上传图片时出现以下错误:

访问 XMLHttpRequest 在 'http://172.16.1.34:1980/api/accounts/uploadAvatar' 来自原点 'http://172.16.1.35:3000' 已被 CORS 策略阻止:否 请求中存在“Access-Control-Allow-Origin”标头 资源。

我也尝试如下更改 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>();
    

请问大家有什么意见吗?

编辑:控制台中的返回标题如下

请求网址:http://172.16.1.34:1980/api/accounts/uploadAvatar 推荐人政策:降级时无推荐人日期:2020 年 4 月 14 日,星期二 03:50:49 GMT 服务器:Microsoft-IIS/10.0 传输编码:分块 X-Powered-By: ASP.NET 接受: application/json, text/plain, / Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 授权:承载 哎呀…… 连接:保持活动内容长度:22869 内容类型: application/json;charset=UTF-8 主机:172.16.1.34:1980 来源: http://172.16.1.35:3000推荐人: http://172.16.1.35:3000/create-profile 用户代理:Mozilla/5.0 (Windows NT 10.0;Win64;x64)AppleWebKit/537.36(Khtml,如 Gecko) Chrome/80.0.3987.163 Safari/537.36 fileName: "avatar", mediaType: "image/png",… fileName: "avatar" mediaType: "image/png" buffer: "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6CAYAAACI7Fo9AAAgAE

【问题讨论】:

响应的 HTTP 状态码是什么?您可以使用浏览器开发工具中的网络窗格进行检查。是 4xx 还是 5xx 错误而不是 200 OK 成功响应? @sideshowbarker 它返回了(失败的 net::err_failed)。我用返回标题更新了我的问题。 【参考方案1】:

通过更改对象类型解决的问题是作为图像文件发送到 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",
                $"sbfileExt");

            var saveDbPath = $"sbfileExt";

            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);
        
    

【讨论】:

以上是关于仅在文件上传中出现 Asp.Net Core API CORS 策略错误的主要内容,如果未能解决你的问题,请参考以下文章

在ASP.NET Core 中上传文件

在 ASP.NET Core 中上传文件

ASP.NET Core 文件上传 之 文件签名验证

如何在 asp.net core 中上传文件?

上传图片 asp.net Core

在 ASP.NET Core Web API 中上传文件和 JSON