• 【ASP.NET Core】URL重写


    今天老周和大伙伴们聊聊有关 Url Rewrite 的事情,翻译过来就是 URL 重写。

    这里不得不提一下,URL重定向与重写的不同。

    1、URL重定向是客户端(通常是浏览器)向服务器请求地址A,然后服务器要求重定向到B,返回状态码 301 或 302 给客户端,并且夹带一个 Location 的标头,其值表示要重定向的目标 URL,即B;随后客户端再用B向服务器发起请求,若成功,服务器返回内容并夹带状态码 200。

    2、URL重写只在服务器上转换URL,当客户端请求地址A进入服务器后,服务器自行处理并转向B。最后返回B地址的内容,夹带状态码 200。此过程只在服务器上发生,不需要与客户端进行多次通信。因此浏览器地址栏中的URL也不会发生变化。

     

    -------------------------------------------------- 超级分界线 ------------------------------------------------------

    实现 URL 重写不需要向服务容器注册功能类,但可以在 Service 集合中配置 Options。你需要通过 RewriteOptions 对象来指定重定向的规则。定义规则的方法是实现 IRule 接口。此接口只有一个 ApplyRule 方法。在实现该方法时,根据需要修改 HttpContext.Request.Path 来设置新的 URL。

    ------------------------------------------------------------------------------------------------------------------------

    下面咱们直接上示例,这里我写了一个简单的URL重写规则。

    复制代码
        public sealed class MyRule : IRule
        {
            public void ApplyRule(RewriteContext context)
            {
                var request = context.HttpContext.Request;
                var oldPath = request.Path;
                // 正则表达式来匹配
                var match = Regex.Match(oldPath, "/ft(\\d+)");
    if(match == null || match.Success == false)
                {
                    context.Result = RuleResult.ContinueRules;
                    return;
                }
                // 找出匹配的分组
                var matchedval = match!.Groups[1].Value;
                // 新的URL
                PathString newPath = "/fight-action/" + matchedval;
                request.Path = newPath;  //修改为新URL
                context.Result = RuleResult.SkipRemainingRules;
            }
        }
    复制代码

    这个规则是这样的:客户端请求 https://localhost/ft3,通过正则表达式,找出URL中的数值 3 ,然后改为新的 URL:https://localhost/fight-action/3。即

    https://host/ft{数值}  ---->  https://host/fight-action/{数值}

    为什么要重写 URL 呢,假设网站内部实现某功能的 URL 很长,很难看,很难记忆,用户看到它就想抽它。为了让用户觉得好记好看,在公开的前台 UI 或者 Web API 中使用一个更短更方便记忆的 URL。这又是为何呢?老周做个假设:假设你有个新闻系统,按照最初的开发设计,写一篇新闻的 URL 是 http://killer/news_manager/addnew。嗯,这个路径逻辑清晰、层次分明、表义明了(对开发人员来说,这样好维护,模块化);可对用户来说,他哪管你模块化还是分尸化,他就觉得这太长,不好记,也不好输入。行,咱们给来个 URL 重写,对外公开的 URL 变成 http://killer/addnews,而服务器内部还是转回原来的地址来处理,但客户端是毫无察觉的。

    还有一种情况是网站修改了,后台的结构变了,API 的结构变了,可你懒得把所有前台 UI 改动。于是,你也可以写个 URL 重写规则,让旧 URL 自动转到新的 URL 上,同样客户端毫无察觉的(明修____,暗渡____)。

     

    回到 ASP.NET Core 主体代码,这里为了节省体力和脑力,老周就不做 HTML 页了,直接 MapGet 代表每个页面。

    复制代码
    // 模拟一些路径
    app.MapGet("/", () => "燕双鹰战斗仪");
    app.MapGet("/fight-action/{mode}", (int mode) => mode switch
    {
        0     => "全自动扫射装载中……",
        1     => "装逼两分钟,开挂三小时",
        2     => "无限子弹碾压",
        3     => "我赌你的枪里没有子弹",
        4     => "脑浆警告",
        5     => "像你这样的人应该怎么改变,不会改变的,只有X",
        _     => "外挂已到期"
    });
    复制代码

    路径 /fight-action 后面一段是路由参数 mode,然后这个数值会随同参数 mode 传入lambda 表达式,内部根据 mode 的值返回不同的字符串。

     

    使用 URL 重写我们不需要向服务容器添加依赖注入对象,直接在 HTTP 管线上以中间件方式 Use 一下即可。

    app.UseRewriter();

    不过,这个无参数调用是未添加任何自定义重写规则的,咱们有两种方法添加规则。

    第一种方法:保持 UseRewriter 方法无参数调用,使用服务容器来 Config 一下 RewriteOptions 选项类。这个方法实际是在服务容器中生成了 IOptions<RewriteOptions> 对象,中间件类 RewriteMiddleware 的构造函数会注入这个选项类实例。

    复制代码
        // 以下为 .NET 源代码
        public RewriteMiddleware(
            RequestDelegate next,
            IWebHostEnvironment hostingEnvironment,
            ILoggerFactory loggerFactory,
            IOptions<RewriteOptions> options)
        {
            // ……
            _next = next;
            _options = options.Value;
            _fileProvider = _options.StaticFileProvider ?? hostingEnvironment.WebRootFileProvider;
            _logger = loggerFactory.CreateLogger<RewriteMiddleware>();
        }
    复制代码

    现在,咱们把刚刚写的 MyRule 规则配置一下。

    复制代码
    var builder = WebApplication.CreateBuilder(args);
    // 配置 rewrite options
    builder.Services.Configure<RewriteOptions>(rwo =>
    {
        rwo.Add(new MyRule());
    });
    var app = builder.Build();
    复制代码

     

    第二种方法:在HTTP 管理线中调用 UseRewriter 方法前,直接 new 一个 RewriteOptions 实例,然后添加刚刚写的规则。最后调用 UseRewriter 方法的带参数版本,把 options 传给它即可。

    RewriteOptions rwopt = new();
    rwopt.Add(new MyRule());
    app.UseRewriter(rwopt);

     

    两种方法任选其一就可以了,不需要重复配置。

    现在咱们运行一下示例。

    默认打开主页是这样的。

     

     

    然后把 URL 改为 /ft3。

     

     

    URL 已经跳转,不过浏览器地址栏不会有变化,而且不会返回 301、302 给客户端,因为这个跳转过程是在服务器上完成的。

     

    ------------------------------------ 未知分界线 -------------------------------------------

    其实,RewriteOptions 补充了一些扩展方法,使得咱们在简单重写URL(不需要特复杂的逻辑分析,用正则就能搞定的)时可以不去实现 IRule 接口。故,咱们这个示例可以改成这样更简洁的实现。

    复制代码
    var builder = WebApplication.CreateBuilder(args);
    // 配置 rewrite options
    builder.Services.Configure<RewriteOptions>(rwo =>
    {
        rwo.AddRewrite("ft(\\d+)", "fight-action/$1", true);
    });
    var app = builder.Build();
    复制代码

    第一个参数是正则表达式,括号中表示捕捉为一个分组,第二个参数是新的 URL,其中“$1”表示引用正则表达式中捕捉的分组编号,咱们这个正则表达式中只有一个分组,即捕捉数值的 \d+,所以用 $1 引用它;如果有其他分组,那就依此类推,$2、$3、$4。它的意思就是引用捕捉到这个分组的值。如,匹配 ft2,捕捉到数值 2,然后替换 $1,使新的URL为 fight-action/2。注意在匹配和替换的 URL 都不用“/”开头,反正类库在处理时也会删除“/”的,所以我们就没必须加“/”。

     

    再测试一下。

    运行后,转到 /ft5,结果如下。

     

     

    好了,今天的节目就到此了,下次有空咱们再聊。

     

  • 相关阅读:
    [附源码]java毕业设计高校评教系统
    go拾遗(2)-函数返回数组、多个值、不显示指定返回
    1013 Battle Over Cities 甲级 xp_xht123
    STM32-HAL库07-软件SPI驱动0.96寸OLED
    如何流畅进入Github
    安全-加密与证书
    nacos实现Java和.NetCore的服务注册和调用
    ES系列十二、ES的scroll Api及分页实例
    左程云 递归+动态规划
    【MATLAB源码-第72期】基于matlab的OFDM-IM索引调制系统在高斯,瑞利,莱斯信道误码率对比,对比传统OFDM系统。
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/16278164.html