从 ASP.NET 核心 API 端点获取不受支持的媒体类型的 HttpCode 415 错误
Getting HttpCode 415 error of Unsupported media type from ASP.NET Core API endpoint
我正在尝试从反应代码调用 asp.net 核心 5 API,但我一直从服务器收到错误 415。
这是前端尝试调用的我的服务器端点
public class OauthToken
{
public string TokenId;
}
[AllowAnonymous]
[HttpPost("signin-google")]
[Consumes("application/json")]
public async Task<IActionResult> GoogleLogin(OauthToken userView)
{
....
}
前端代码如下:
const googleResponse = (response) => {
const options = {
method: 'POST',
body: { TokenId: response.tokenId },
mode: 'no-cors',
accepts: "application/json",
cache: 'default',
contentType : "application/json",
}
fetch(config.GOOGLE_AUTH_CALLBACK_URL, options)
.then(r => {
console.log(r)
})
.catch(e=>{
console.log(e)
})
}
下面是我的startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddRoles<ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddCors(opts =>
{
opts.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
//.AllowCredentials();
});
});
services.AddAuthentication()
.AddIdentityServerJwt()
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["AppSettings:JwtSecret"])),
ValidateIssuer = false,
ValidateAudience = false
};
})
.AddGoogle(opt =>
{
opt.ClientId = "MY_CLIENT_ID";
opt.ClientSecret = "MY_CLIENT_SECRET";
opt.SignInScheme = IdentityConstants.ExternalScheme;
})
//.AddTwitter(twitterOptions => { })
.AddFacebook(facebookOptions => {
facebookOptions.AppId = Configuration["Authentication:Facebook:AppId"];
facebookOptions.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
});
services.AddControllersWithViews();
services.AddRazorPages();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseCors("AllowAll");
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "/api/v1/{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
我不知道问题出在哪里。
请帮我解决这个问题。
谢谢。
根据您的评论,我已经测试并重现了您的问题,您可以在下面查看:
Reproduced Issue:
How do I call the endpoint to get the data get to it?:
如果你可以查看你的 client-side code
和 HTTP Verb
它应该在 FromBody
内发送请求但是你没有那样发送,所以你有两种方法可以实现那:
Way 1 : Set [FromBody] On Method:
[AllowAnonymous]
[HttpPost("signin-google")]
[Consumes("application/json")]
public async Task<IActionResult> GoogleLogin([FromBody] OauthToken userView)
{
return Ok();
}
Output:
Way 2 : Set TokenId as string on Method:
[AllowAnonymous]
[HttpPost("signin-google")]
[Consumes("application/json")]
public async Task<IActionResult> GoogleLogin(string TokenId)
{
return Ok();
}
Output:
Note: So you could try above steps to call your API endpoint accordingly. I noticed that problem was in API routing
and method argurment
additionally, I would suggest you to have a look on our
offical docs for indepth insight here
希望它能按预期为您提供指导,帮助您解决问题。
经过以下更改后,我终于让代码正常工作了:
我注意到OathTokenclass的TokenId属性没有getter也没有setter。所以,我更新如下:
public class OauthToken
{
//added {get; set;}
public string TokenId { get; set; }
}
将提取请求的主体从对象更改为 blob,如下所示:
const tokenBlob = new Blob([JSON.stringify({ TokenId: response.tokenId }, null, 2)], { type: 'application/json' });
将请求的模式从“no-cors”更改为“cors”,因为 Cors 已经在项目startup.cs class 中声明
因此,更新后的工作提取请求如下:
const googleResponse = (response) => {
const tokenBlob = new Blob([JSON.stringify({ TokenId: response.tokenId }, null, 2)], { type: 'application/json' });
const options = {
method: 'POST',
body: tokenBlob,
mode: 'cors',
accepts: "application/json",
cache: 'default',
contentType : "application/json",
}
fetch(config.GOOGLE_AUTH_CALLBACK_URL, options)
.then(r => {
r.json().then(user => {
console.log(user.tokenId);
});
})
.catch(e=>{
console.log(e)
})
}
端点处的代码如下:
public class OauthToken
{
public string TokenId { get; set; }
}
[AllowAnonymous]
[Consumes("application/json")]
[HttpPost("signin-google")]
public async Task<IActionResult> GoogleLogin([FromBody] OauthToken clientToken)
{
return Ok(clientToken);
}
我想这可能会对面临此类问题的其他人有所帮助。
谢谢
我正在尝试从反应代码调用 asp.net 核心 5 API,但我一直从服务器收到错误 415。
这是前端尝试调用的我的服务器端点
public class OauthToken
{
public string TokenId;
}
[AllowAnonymous]
[HttpPost("signin-google")]
[Consumes("application/json")]
public async Task<IActionResult> GoogleLogin(OauthToken userView)
{
....
}
前端代码如下:
const googleResponse = (response) => {
const options = {
method: 'POST',
body: { TokenId: response.tokenId },
mode: 'no-cors',
accepts: "application/json",
cache: 'default',
contentType : "application/json",
}
fetch(config.GOOGLE_AUTH_CALLBACK_URL, options)
.then(r => {
console.log(r)
})
.catch(e=>{
console.log(e)
})
}
下面是我的startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddRoles<ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddCors(opts =>
{
opts.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
//.AllowCredentials();
});
});
services.AddAuthentication()
.AddIdentityServerJwt()
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["AppSettings:JwtSecret"])),
ValidateIssuer = false,
ValidateAudience = false
};
})
.AddGoogle(opt =>
{
opt.ClientId = "MY_CLIENT_ID";
opt.ClientSecret = "MY_CLIENT_SECRET";
opt.SignInScheme = IdentityConstants.ExternalScheme;
})
//.AddTwitter(twitterOptions => { })
.AddFacebook(facebookOptions => {
facebookOptions.AppId = Configuration["Authentication:Facebook:AppId"];
facebookOptions.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
});
services.AddControllersWithViews();
services.AddRazorPages();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseCors("AllowAll");
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "/api/v1/{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
我不知道问题出在哪里。 请帮我解决这个问题。 谢谢。
根据您的评论,我已经测试并重现了您的问题,您可以在下面查看:
Reproduced Issue:
How do I call the endpoint to get the data get to it?:
如果你可以查看你的 client-side code
和 HTTP Verb
它应该在 FromBody
内发送请求但是你没有那样发送,所以你有两种方法可以实现那:
Way 1 : Set [FromBody] On Method:
[AllowAnonymous]
[HttpPost("signin-google")]
[Consumes("application/json")]
public async Task<IActionResult> GoogleLogin([FromBody] OauthToken userView)
{
return Ok();
}
Output:
Way 2 : Set TokenId as string on Method:
[AllowAnonymous]
[HttpPost("signin-google")]
[Consumes("application/json")]
public async Task<IActionResult> GoogleLogin(string TokenId)
{
return Ok();
}
Output:
Note: So you could try above steps to call your API endpoint accordingly. I noticed that problem was in
API routing
andmethod argurment
additionally, I would suggest you to have a look on our offical docs for indepth insight here
希望它能按预期为您提供指导,帮助您解决问题。
经过以下更改后,我终于让代码正常工作了:
我注意到OathTokenclass的TokenId属性没有getter也没有setter。所以,我更新如下:
public class OauthToken { //added {get; set;} public string TokenId { get; set; } }
将提取请求的主体从对象更改为 blob,如下所示:
const tokenBlob = new Blob([JSON.stringify({ TokenId: response.tokenId }, null, 2)], { type: 'application/json' });
将请求的模式从“no-cors”更改为“cors”,因为 Cors 已经在项目startup.cs class 中声明
因此,更新后的工作提取请求如下:
const googleResponse = (response) => {
const tokenBlob = new Blob([JSON.stringify({ TokenId: response.tokenId }, null, 2)], { type: 'application/json' });
const options = {
method: 'POST',
body: tokenBlob,
mode: 'cors',
accepts: "application/json",
cache: 'default',
contentType : "application/json",
}
fetch(config.GOOGLE_AUTH_CALLBACK_URL, options)
.then(r => {
r.json().then(user => {
console.log(user.tokenId);
});
})
.catch(e=>{
console.log(e)
})
}
端点处的代码如下:
public class OauthToken
{
public string TokenId { get; set; }
}
[AllowAnonymous]
[Consumes("application/json")]
[HttpPost("signin-google")]
public async Task<IActionResult> GoogleLogin([FromBody] OauthToken clientToken)
{
return Ok(clientToken);
}
我想这可能会对面临此类问题的其他人有所帮助。 谢谢