D-17 路由 ? Routing

路由的介绍

在历经昨天网页程序的基础知识的介绍之後,今天小光终於要开始进入网页程序的开发了,所以今天小光会学到甚麽东西呢。

本文同步放置於此

路由 Routing

「哇,昨天的基础知识真的是让我收获良多阿」
小光一进公司就探头探脑地走到大头的座位前,然而大头仍埋头在需求文件中努力开发,但是他还是回应了小光的话。
「哈哈哈,我知道你昨天听的头昏脑胀的,不过基础知识很重要,尤其是老K前辈跟你介绍的那些。」
听到这里小光忍不住吐舌头做鬼脸来表示他的不好意思,接着突然想到甚麽似的问个问题。
「前辈,关於昨天Request Pipeline中的Routing是甚麽阿。」
这时刚好大头开发告一段落後,他喝了杯水并抬起头来跟小光这麽说。
「那个阿,简单讲就是怎麽样透过URL到你程序的指引阿。」
听到这个回答,小光表现出似懂非懂的样子,所以看到小光的表情後大头继续说下去。
「怎麽,想要更进一步了解一下吗。」
这时小光很猛烈的点头,看到小光的样子大头就继续说下去。
「好吧,那我们就来了解一下甚麽是路由以及如何设定他。」

路由是甚麽

这边先看一下Routing是甚麽,其中MSDN中说「路由会负责比对传入的 HTTP 要求,并将这些要求分派至应用程序的可执行端点」,所以简单讲来就是请求如何透过Url网址来到达我们写的Code之间的对应,然而不同的网应程序类别他的对应也就不同,所以我们这边以MVC跟WebApi为例子来说明如何设定路由,当然有兴趣了解gRpc跟RazorPage的朋友们可以详细看一下Routing这篇文章。

路由设定的地方

在Mvc与WebApi设定路由主要要设定两个地方,StartupControllerAttribute,所以接下来分别介绍这两个部分要设定甚麽,首先先介绍Startup的设定。

Startup的设定地方

这部分主要要设定的东西如下列所示,首先介绍Mvc的设定。

Mvc路由的设定内容

public void Configure(IApplicationBuilder app, 
    IWebHostEnvironment env)
{
    .
    .
    .
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
    .
    .
    .
}

透过上述设定,大部分的路由都会走default这个设定,例如/Products/Details/5这样的Url就会对应到以下的程序码的Details并且带int参数的Action内。

public class ProductsController : Controller
{
    public IActionResult Details(int id)
    {
        ...
    }
}

不过其实上述例子中的MapControllerRoute也可以简化为下列例子。

    app.MapDefaultControllerRoute();

然後路的设定可以设定多组,例如下列例子。

    endpoints.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
    endpoints.MapControllerRoute(name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");

在上述例子中Url为/Blog/Blog/Article/Blog/{any-string}是唯一符合 blog 路由的 URL 路径,而且会对应到BlogController下的Article这个Action。

public class BlogController : Controller
{
    public RouteData Article ()
    {
        return ControllerContext.RouteData;
    } 

    public RouteData Index ()
    {
        return ControllerContext.RouteData;
    } 
}

所以Url跟结果会如下表所示。

Url 结果
/Blog/xxx {"dataTokens":{},"routers":[],"values":{"controller":"Blog","action":"Article","article":"xxx"}}
/Blog/Article {"dataTokens":{},"routers":[],"values":{"controller":"Blog","action":"Article","article":"Article"}}
/Blog/Index {"dataTokens":{},"routers":[],"values":{"controller":"Blog","action":"Article","article":"Index"}}
/ Home的Index的页面
/Home Home的Index的页面

WebApi路由的设定内容

所以介绍完了Mvc的设定方式後接下来跟大家介绍WebApi在Startup怎麽设定。

public void Configure(IApplicationBuilder app, 
    IWebHostEnvironment env)
{
    .
    .
    .
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
    .
    .
    .
}

相较於Mvc的设定来说,WebApi的设定简单许多,因为有许多设定都是挂在Controller上的Attribute上,所以我们接下来说明一下Controller要设定的地方。

Controller设定的地方

刚刚说明完Startup要设定的部分之後,接下来我们要来看Controller设定的地方,这部分可以参考一下Mvc Routing的说明。关於Controller设定路由的部分可以分成两种Attribute来说明,这两种分别为RouteHTTP 动词,因为我们在Startup使用的是MapControllers,所以如果没特别设定的话预设会先使用预设的路由设定{controller=Home}/{action=Index}/{id?},接下来先看下列Route的范例。

[Route("[controller]/[action]")]
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("[controller]/[action]")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [Route("[controller]/[action]")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

首先在[]内的会对应到class上的controlleraction例如上面的Home这个Controller跟Index跟About这个Action,同时也可以特别指定到对应的路由例如上述的[Route("Home")],最後class上挂的attribute会继承到方法上面所以其实方法上的[Route("[controller]/[action]")]可以省略。
再来在Restful上面会指定HttpMethod所以要搭配下列attribute使用让Action只能接受特定HttpMethod

  • HttpGet
  • HttpPost
  • HttpPut
  • HttpDelete
  • HttpHead
  • HttpPatch
    实际设定如下。
[Route("api/[controller]")]
[ApiController]
public class Test2Controller : ControllerBase
{
    [HttpGet]   // GET /api/test2
    public IActionResult ListProducts()
    {
        ...
    }

    [HttpGet("{id}")]   // GET /api/test2/xyz
    public IActionResult GetProduct(string id)
    {
       ...
    }

    [HttpGet("int/{id:int}")] // GET /api/test2/int/3
    public IActionResult GetIntProduct(int id)
    {
        ...
    }

    [HttpGet("int2/{id}")]  // GET /api/test2/int2/3
    public IActionResult GetInt2Product(int id)
    {
        ...
    }
}

其中上述例子中可以看到[HttpGet("{id}")]这个的设定就是同时结合HttpMethod跟Route,简单说明就是绑订在HttpGet并且url为/api/test2/xyz的状况下才会使用者个Action,其中url的xyz是任意字串。
所以路由就介绍到这里告一段落了。

後记

「前辈,没想到光一个Url的对应到程序码就有这麽大的学问阿。」
听完之後小光把他的感想告诉大头,并且一边抄写他的笔记。
「哈哈哈,你才知道阿,不过这边要注意的是避免写出模凌两可的路由喔,好一点在开发时会告诉你模凌两可,如果写得不好你会走到不是你想要的Action喔。」
所以今天就在大头的叮咛下结束了路由的课程。


<<:  Kotlin Android 第23天,从 0 到 ML - CameraX

>>:  事件监听的this:「这个」到底是哪一个?

[Day 28] Edge Impulse + BLE Sense实现影像分类(下)

=== 书接上回,[Day 27] Edge Impulse + BLE Sense实现影像分类(上...

[Python学习笔记] 文件I/O-Day2

读取键盘输入 input函数 读取和写入标准输入和输出 开启的txt档案会写入 程序中的"...

[Day13] THM Res

今天这一题是针对 Redis 服务的攻击,对於打腻 Web 的人应该会觉得满有趣的(?)。 网址:h...

Day 23 实时时钟(real-time)与系统时钟(system clock)

嵌入式系统,会因为时间关系,系统和用户的任务经常要定期的重新设定排程。所以对於某个特定时间就需要透过...

[Day 5] Course 1_Foundation - 资料分析工具及职涯探索

《30天带你上完 Google Data Analytics Certificate 课程》系列将...