【发布时间】:2020-06-10 15:38:49
【问题描述】:
我正在尝试让我的 ReactJS 应用程序(在 AWS S3 机器上)PUT 请求与我的服务器 API(在 AWS Windows EC2 机器上)一起工作。似乎我被发出的飞行前消息绊倒了。我一直在寻找如何处理这个问题并遇到了这两个 stackoverflow 帖子:
Enable OPTIONS header for CORS on .NET Core Web API
How to handle OPTION header in dot net core web api
我已确保 IIS 接受 OPTIONS 动词并添加了所描述的中间件。我可以看到通过日志记录调用了 OPTIONS 预检处理,但由于某种原因,我仍然收到 CORS 错误。列出了下面代码的主要部分,任何帮助将不胜感激。
ReactJS PUT 请求
var myHeaders = new Headers();
myHeaders.append('Accept', 'application/json');
myHeaders.append('Content-Type', 'application/json-patch+json');
var rawObject = {
Name: this.state.recipeEdit.name,
Type: this.state.recipeTypeEdit,
Description: this.state.recipeEdit.description,
Ingredients: this.state.recipeIngredients,
Steps: this.state.recipeSteps,
};
var requestOptions = {
method: 'PUT',
headers: myHeaders,
body: JSON.stringify(rawObject),
redirect: 'follow',
};
fetch(this.state.url, requestOptions)
.then((response) => response.json())
.then((data) => {
this.setState({ recipeDetail: data });
});
中间件类
public class OptionsMiddleware
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly RequestDelegate _next;
public OptionsMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext context)
{
return BeginInvoke(context);
}
private Task BeginInvoke(HttpContext context)
{
if (context.Request.Method == "OPTIONS")
{
log.Error("Handling the OPTIONS preflight message");
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { (string)context.Request.Headers["Origin"] });
context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" });
context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "GET, POST, PUT, DELETE, OPTIONS" });
context.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
context.Response.StatusCode = 200;
return context.Response.WriteAsync("OK");
}
log.Error("Invoking message");
return _next.Invoke(context);
}
}
public static class OptionsMiddlewareExtentions
{
public static IApplicationBuilder UseOptions(this IApplicationBuilder builder)
{
return builder.UseMiddleware<OptionsMiddleware>();
}
}
Startup.cs 中的 CORS 配置
public void ConfigureServices(IServiceCollection services)
{
log.Error("Entered ConfigureServices");
try
{
#if DEBUG
services.AddCors();
#else
services.AddCors(o => o.AddPolicy("MyCorsPolicy", builder =>
{
builder.SetIsOriginAllowed((host) => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
#endif
services.AddControllersWithViews().AddNewtonsoftJson();
services.AddControllersWithViews(options =>
{
options.InputFormatters.Insert(0, GetJsonPatchInputFormatter());
});
services.AddMvc(options => options.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddMvc(options => options.Filters.Add(typeof(homebakeExceptionFilter)));
#if USE_SQLITE
log.Error("Using SQLITE");
services.AddDbContext<SqliteDbContext>(options =>
{
options.UseSqlite("Data Source=./homebake.db");
});
#else
services.AddDbContext<AppDbContext>(options =>
{
options.UseInMemoryDatabase("homebakeapp-api-in-memory");
});
#endif
log.Error("Adding services");
services.AddScoped<IIngredientRepository, IngredientRepository>();
services.AddScoped<IRecipeStepRepository, RecipeStepRepository>();
services.AddScoped<IRecipeRepository, RecipeRepository>();
services.AddScoped<IIngredientService, IngredientService>();
services.AddScoped<IRecipeStepService, RecipeStepService>();
services.AddScoped<IRecipeService, RecipeService>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
log.Error("Adding auto mapper");
services.AddAutoMapper(typeof(Startup));
}
catch (System.Exception ex)
{
log.Error(ex.Message);
if (ex.InnerException != null )
log.Error(ex.InnerException);
}
}
private static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter()
{
var builder = new ServiceCollection()
.AddLogging()
.AddMvc()
.AddNewtonsoftJson()
.Services.BuildServiceProvider();
return builder
.GetRequiredService<IOptions<MvcOptions>>()
.Value
.InputFormatters
.OfType<NewtonsoftJsonPatchInputFormatter>()
.First();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddLog4Net();
log.Error("Entered Configure");
app.UseOptions();
#if DEBUG
app.UseCors(options => options.WithOrigins("http://localhost:3000").AllowAnyMethod().AllowAnyHeader());
#else
log.Error("Using cors policy");
app.UseCors("MyCorsPolicy");
#endif
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
//app.use
app.UseHttpsRedirection();
log.Error("Using MVC");
app.UseMvc();
}
【问题讨论】: