【.Net core】ASP.NET Core 中的路由
2021-03-18 13:25
标签:mat web pcs als value 重点 auth netcore 有用 路由在任何一门编程语言的web框架中,都是一个重点,只有知道路由规则,才能通过URL映射服务端的请求处理。本篇描述的路由系统.netcore版本是.net core 3.x。 将用户请求地址=>映射为一个请求处理器 路由负责匹配传入的 HTTP 请求,然后将这些请求发送到应用的可执行终结点。 一个终结点(EndPoint)就是一个处理请求的委托。终结点是一个抽象概念,不止服务于常见的mvc模式。 在所有 如下代码 上面的代码像不像 好了,说回我们的 再说说MapGet: 类似的,还有 再看下面的代码: 上面的代码説明以下几点: 上面的代码有两个终结点,其中只有一个终结点附加了授权策略。 通过上面的基础路由,我们可以看到,路由系统通过强大的终结点概念构建在中间件管道之上。 注意看上面的代码 在 在 查看如下代码: 何为终端中间件?终端中间件:在匹配 使用场景 一句话:通过 当路由中间件执行时,从当前请求路由到 常见的路由约束 关于路由约束还有正则表达式,自定义路由约束等等内容,但是其实并不常用,更多内容请阅读微软官方文档 ASP.NET Core控制器使用的是Routing 中间件去匹配请求的URL并将其映射至Actions 一般会有一个路由模板: Action匹配,要么是常规路由(Conventionally-routed),要么是属性路由(attributes-routed) MVC的控制器-视图应用,基本都是使用上面的路由模板。 大概:URL 路径 简便方法: 此方法与上面等价 REST API,微软建议使用属性路由。具体也是跟 路由通过 如上所述, 在 那么类比, 也正是因为 微软官方把这个叫中间件管道分支,博主认为这还是可以作为自定义路由的方式来看待。 好了路由的内容就讲到这儿,微软有时候是封装的太好了,太优雅,但是我们还是要去探究一下,所谓知其然还要知其所以然。 https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/routing?view=aspnetcore-3.1 https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-3.1 https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/routing?view=aspnetcore-3.1 https://www.cnblogs.com/jionsoft/archive/2019/12/29/12115417.html https://godoc.org/github.com/gin-gonic/gin#RouterGroup 【.Net core】ASP.NET Core 中的路由 标签:mat web pcs als value 重点 auth netcore 有用 原文地址:https://www.cnblogs.com/RandyField/p/12770992.html1.路由
Func
any controller any action
1.1 终结点-EndPoint
1.2 原理
请求路径 与 终结点的对应关系,请求抵达时才能匹配找到合适的终结点来处理我们的请求,这步相当于定义路由。asp.net core 3.x的中间件路由默认差不多就这样了,此时可以定义自己的中间件,放在步骤3后面,拿到终结点做一些高级处理。微软定义的一些中间件也是这个套路。2.路由基础
Asp.net core的代码中,路由都是在Startup.Configure中的中间件管道注册app.UseRouting();
app.UseEndpoints(endpoints=>{
endpoints.MapGet("/",async context=>
{
await context.Response.WriteAsync("Hello,World!");
});
});
Koa.jsrouter.get("/",async(ctx)=>{
})
asp.net core,这里使用了一对中间件来注册路由:UseRouting,UseEndpoints
get / =>将会执行后面的委托GET,或者URL不是/,则找不到路由匹配,就会返回著名的4042.1 再看终结点
MapGet就算是定义了一个终结点,一个终结点具有以下内容:
url+http 请求Map,MapPost,MapPut,MapDelete,在ASP.NET Core同系列的其他框架连接到路由系统,是通过下面的方法:
Razor Pages是通过MapRazorPages
Controllers是通过MapControllers
Signal是通过MapHub
gRPC是通过MapGrpcService
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Matches request to an endpoint.
app.UseRouting();
// Endpoint aware middleware.
// Middleware can use metadata from the matched endpoint.
app.UseAuthentication();
app.UseAuthorization();
// Execute the matched endpoint.
app.UseEndpoints(endpoints =>
{
// Configure the Health Check endpoint and require an authorized user.
endpoints.MapHealthChecks("/healthz").RequireAuthorization();
// Configure another endpoint, no authorization requirements.
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
endpoints.MapHealthChecks("/healthz").RequireAuthorization();
MapHealthChecks 调用添加运行状况检查终结点。 将 RequireAuthorization 链接到此调用会将授权策略附加到该终结点。UseAuthentication 和 UseAuthorization 会添加身份验证和授权中间件。 这些中间件位于 UseRouting和 UseEndpoints 之间,因此它们可以:
UseRouting 选择的终结点。UseEndpoints 发送到终结点之前应用授权策略。2.2 终结点元数据
MapHealthChecks,如果请求healthz,就会授权检查。说明,终结点可以附加额外的数据,称为元数据
routing-aware中间件处理3.Netcore 3.x中的路由概念
3.1 终结点定义
RequestDelegate
EndpointDataSource列出终结点集合app.UseRouting();
app.Use(next => context =>
{
var endpoint = context.GetEndpoint();
if (endpoint is null)
{
return Task.CompletedTask;
}
Console.WriteLine($"Endpoint: {endpoint.DisplayName}");
if (endpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine("Endpoint has route pattern: " +
routeEndpoint.RoutePattern.RawText);
}
foreach (var metadata in endpoint.Metadata)
{
Console.WriteLine($"Endpoint has metadata: {metadata}");
}
return Task.CompletedTask;
});
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
RouteEndpointcontext.GetEndpoint();通过这句,就能检索终结点,调用RequestDelegateUseRouting 中间件使用 SetEndpoint方法将终结点附加到当前上下文。 可以将 UseRouting 中间件替换为自定义逻辑,同时仍可获得使用终结点的益处。 终结点是中间件等低级别基元,不与路由实现耦合。 大多数应用都不需要将 UseRouting 替换为自定义逻辑。说白了,路由是可以自定义的。UseRouting之前的中间件:修改请求的属性
UseRewriterUseHttpMethodOverrideUsePathBaseUseRouting与UseEndpoints之间的中间件:执行终结点前处理路由结果
UseAuthorization 和 UseCors 做出安全决策。4.终端中间件与路由
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Approach 1: Writing a terminal middleware.
app.Use(next => async context =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Hello terminal middleware!");
return;
}
await next(context);
});
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// Approach 2: Using routing.
endpoints.MapGet("/Movie", async context =>
{
await context.Response.WriteAsync("Hello routing!");
});
});
}
url的中间件
UseEndpoints中执行
UseAuthorization 和UseCors.
UseAuthorization 或 UseCors 使用终端中间件需要与授权系统进行手动交互。
5.URL匹配
url找到委托HttpContext上的请求功能,它会设置 Endpoint和路由值(Route Values):
GetEndpoint 获取终结点。HttpRequest.RouteValues 将获取路由值的集合。6.路由约束
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/hello/{name:alpha}", async context =>
{
var name = context.Request.RouteValues["name"];
await context.Response.WriteAsync($"Hello {name}!");
});
});
{id:int}``{name:alpha}``{active:bool},等等,更多请参考官方说明7.Asp.net core 3.x中的路由
Startup中,或者attributes
7.1 常规路由
Startup.Configureapp.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
/使用路由模板默认Home控制器和Index操作。 URL 路径/Home使用路由模板默认Index操作,这个跟以前的ASP.NET 4.x,是一样,不赘述了。endpoints.MapDefaultControllerRoute();
7.2 属性路由
ASP.NET Web API 2 中的属性路由差不了太多,其中的细节与技巧留着以后总结吧,多则惑少则多。 app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
UseRouting和UseEndpoints中间件注册。如果要使用控制器(别忘了,你是可以自定义路由的):
UseEndpoints中调用MapControllers,映射属性路由控制器MapControllerRoute 和 MapAreaControllerRoute映射常规路由控制器7.3.自定义路由
endpoints.MapControllerRoute()与endpoints.MapControllers();都是微软为开发者行的方便,将用户请求地址=>匹配到MVC的控制器(Controller)与Action。那我们是完全摒弃微软MVC模式下那一套路由法则,走自定义路由,这里主要利用中间件来实现,也就是上面说的那些在匹配url的中间件。这也是Koa.js和Gin等不同语言的下的web框架实现http请求路由匹配内部方法。详情请阅读【对比学习】Koa.js、Gin与Asp.net core-中间件koa.js的中间件分类
app.use()
router.get(‘/news‘,async(ctx,next)=>{await next();})
匹配一切
asp.net core也是可以这样来看app.Use(async(context,next)=>
{
await context.Response.WriteAsync("match everything");
});
app.Use(),短路一切,任何路由都会只返回match everything,后面再多中间件都不会执行,如果想继续匹配就需要next
app.Use(async(context,next)=>
{
await context.Response.WriteAsync("first");
await next();//await next.Invoke();
});
app.Use(async(context,next)=>
{
await context.Response.WriteAsync("second");
});
Run():只有一个RequestDelegate委托,参数只有HttpContext,没有next所以Run()自然能作为一个终结点.app.Run(async context =>
{
await context.Response.WriteAsync("first");
});
RequestDelegate,所以app.Run()作为终结点的委托。匹配根 ‘/‘
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
var endpoint = context.GetEndpoint();
await context.Response.WriteAsync("/");
});
});
匹配指定路由
app.UseEndpoints与MapGet
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
var endpoint = context.GetEndpoint();
await context.Response.WriteAsync("Hello World!");
});
endpoints.MapGet("/test1", async context =>
{
var endpoint = context.GetEndpoint();
await context.Response.WriteAsync("test1");
});
});
app.Map() app.Map("/map", app =>
{
app.Run(async context =>
{
await context.Response.WriteAsync("我是map");
});
});
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Map("/user/login", HandleLogin);
}
private static void HandleLogin(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("登录成功");
});
}
}
app.Map("/user", level1App => {
level1App.Map("/login", level2AApp => {
// "/user/login" processing
});
level1App.Map("/info", level2BApp => {
// "/user/user" processing
});
});
Gin里面也有类似的,叫路由组func main() {
r := gin.Default()
userGroup := r.Group("/user")
{
userGroup.GET("/index", func(c *gin.Context) {...})
userGroup.GET("/login", func(c *gin.Context) {...})
userGroup.POST("/login", func(c *gin.Context) {...})
}
shopGroup := r.Group("/shop")
{
shopGroup.GET("/index", func(c *gin.Context) {...})
shopGroup.GET("/cart", func(c *gin.Context) {...})
shopGroup.POST("/checkout", func(c *gin.Context) {...})
// 嵌套路由组
xx := shopGroup.Group("xx")
xx.GET("/oo", func(c *gin.Context) {...})
}
r.Run()
}
8.参考链接
文章标题:【.Net core】ASP.NET Core 中的路由
文章链接:http://soscw.com/index.php/essay/65796.html