惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
Martin Fowler
Martin Fowler
云风的 BLOG
云风的 BLOG
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
The Blog of Author Tim Ferriss
大猫的无限游戏
大猫的无限游戏
A
About on SuperTechFans
小众软件
小众软件
博客园_首页
博客园 - 聂微东
罗磊的独立博客
Recent Announcements
Recent Announcements
U
Unit 42
N
Netflix TechBlog - Medium
Blog — PlanetScale
Blog — PlanetScale
阮一峰的网络日志
阮一峰的网络日志
博客园 - 叶小钗
V
V2EX
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
Stack Overflow Blog
Stack Overflow Blog
博客园 - Franky
D
DataBreaches.Net
Last Week in AI
Last Week in AI

寒夏摸鱼站

影评《诺曼底72小时》 - 寒夏摸鱼站 Rust 的那些内置 Trait - 寒夏摸鱼站 教你造一台光棱坦克 - 寒夏摸鱼站 Vite 与 Rust 的 Monorepo 前后端联合开发 - 寒夏摸鱼站 Rust 中的全局对象实现 - 寒夏摸鱼站 Stable Diffusion 拆解分析笔记 #2 - 寒夏摸鱼站 Stable Diffusion 拆解分析笔记 #1 - 寒夏摸鱼站 加密博客测试 - 寒夏摸鱼站 FUTURE 甜点谜题 —— 出题人杂谈 Vol.1 - 寒夏摸鱼站 JS 模块系统 - 寒夏摸鱼站 教你造一台幻影坦克 - 寒夏摸鱼站 随机迷宫生成算法 - 寒夏摸鱼站 Lambda 演算 - 寒夏摸鱼站 博客搭建Log #5 - 寒夏摸鱼站 留言板 - 寒夏摸鱼站 SZTU NEW STAR CTF 游记 - 寒夏摸鱼站 使用容器化技术在 Linux 服务器上部署 OlivaDice - 寒夏摸鱼站 Rust 下的 Shell 管道调用 - 寒夏摸鱼站 柏林噪声与地形生成 - 寒夏摸鱼站 PHP 序列化的生成与解析 - 寒夏摸鱼站 猴子都能明白的 Typecho 建站教程 #4 - 寒夏摸鱼站 猴子都能明白的 Typecho 建站教程 #3 - 寒夏摸鱼站 猴子都能明白的 Typecho 建站教程 #2 - 寒夏摸鱼站 猴子都能明白的 Typecho 建站教程 #1 - 寒夏摸鱼站 博客搭建Log #4 - 寒夏摸鱼站 后缀自动机&广义后缀自动机 - 寒夏摸鱼站 字符串基础与 KMP 算法 - 寒夏摸鱼站 博客搭建Log #3 - 寒夏摸鱼站 快速傅里叶算法 - 寒夏摸鱼站 博客搭建Log #2 - 寒夏摸鱼站
关于地址重写与路由分发的研究 - 寒夏摸鱼站
2021-06-24 · via 寒夏摸鱼站

关于地址重写与路由分发的研究

目录
  • 什么是地址重写
  • 什么是路由分发
  • 路由分发的背后
  • 傻瓜般的路由分配系统
  • 最后
  • 什么是地址重写

    由作者本人经验总结,不保证定义准确性,只当大致了解即可

    地址重写又称 URL 重写,是由服务器所支持的,可以用来隐藏真实的地址以及实现伪静态功能。

    地址重写会遵循一套特定的规则,而不同的服务器框架会用不同的规则,一般常见的服务器框架有 IIS、Apache 和 Nginx,他们的重写规则不完全相同。

    简单来讲,服务器在对地址进行重写时,做的就是替换工作,如把:https://xxxxxx.xxx/p/123 给换成 https://xxxxxx.xxx/passage.php?id=123,我们通过这种方法隐藏了真正起作用的 API —— passage.php,可以一定程度上防止被扒裤衩,还可以使得 URL 更加漂亮。

    什么是路由分发

    由作者本人经验总结,不保证定义准确性,只当大致了解即可

    当然在网站里肯定不止有一个简简单单的 /p/123,还有很多诸如 /catagory/none/tag/none 等其他不同的 API,你当然可以直接在地址重写里面把这些 API 全部实现进去,但是还有另一种方法,那就是路由分发。

    在使用路由分发机制时,我们一般会把重写规则变成如下(简单示意):

    https://xxxxxx.xxx/p/123→https://xxxxxx.xxx/index.php?p/123\text{https://xxxxxx.xxx/p/123} \to \text{https://xxxxxx.xxx/index.php?p/123}

    非常简单,就是把 URL 的路径截出来,直接放在主页后面,转换成查询字符串的模式,这样我们在 index.php 里直接调用 $_SERVER['QUERY_STRING'] 就能获得 p/123

    然后就是路由分发发挥作用的时候了 —— 把 p/123 解析成对应的 API 地址,然后调用。

    这种处理伪静态 URL 的方法也是 Typecho(v1.2) 目前所使用的方法。

    路由分发的背后

    地址重写比较简单,只需要在网上找找不同服务器框架的重写规则,你也可以很快地写出一份 rewrite 文件,真正好玩的其实是路由分发。

    路由分发的精髓就是解析查询字符串。访问一个 URL 的时候其实我们基本上就需要处理两个东西 —— GET 请求和 POST 请求,其中 POST 请求我们根本不需要管,因为它不会出现在查询字符串里,重要的是处理查询字符串中的 GET 请求。

    因为此时我们已经完全脱离了服务器自己的 GET 查询系统(整个查询字符串都被我们用来当路由了),所以只需要根据自己的需求来解析就可以了。一般情况可以用大量的正则匹配来完成(同样是 Typecho 的做法),把查询字符串解析成标准的 URL 访问 API,或者直接在路由分发系统里面调用 API,都可以起到隐藏 API 的功能。

    路由分发除了隐藏 API 以外,还可以用来把外链转换成内链,如果遇上了某些又臭又长的外链非常有用,这也是博客系统经常用的功能。

    傻瓜般的路由分配系统

    这个例子是傻瓜式匹配路由路径,以 @ 作为分隔符来划分路径部分和 GET 部分,最终的 URL 呈现大概是这样:https://xxxxxx.xxx/index.php?action/link@do=get&id=123

    如果你再进一步进行地址重写,你可以把它以假乱真成这样:https://xxxxxx.xxx/action/link@do=get&id=123,这个有点碍眼的小问号就没了。当然你还可以修改一下代码,把 @ 给换成 ?,让这段 URL 看起来更正常一点:https://xxxxxx.xxx/action/link?do=get&id=123

    我们选择在路由系统内部调用 API(include 实现)。在 API 中直接调用 rRouter::$queryStringrRouter::$getrRouter::$post 可以分别得到真正的查询字符串 do=get&id=123、get 数组(即代替原来的 $_GET)和 post 数组(原 $_POST)。

    add 函数是用来添加路径的,当然理想状态是用正则匹配啥的,但是简单的查表对应也够了。

    to404 函数看字面就知道是干嘛的了。

    despatch 函数就是真正用来进行路由分发的,所有的解析都发生在这里。

    <?php
    // rRouter.php
    class rRouter {
      static public $queryString, $get, $post;
      static private $p_list = array();
    
      static public function add($route, $path) {
        self::$p_list[$route] = $path;
      }
    
      static public function despatch() {
        self::$post = $_POST;
        $qry_ = $_SERVER['QUERY_STRING'];
    
        // 处理查询字符串
        $qpos_ = stripos($qry_, '@');
        if ($qpos_ !== false) {
          $qpth_ = substr($qry_, 0, $qpos_);
          self::$queryString = substr($qry_, $qpos_ + 1);
        }
        else {
          $qpth_ = $qry_;
          self::$queryString = '';
        }
    
        // 如果路径不存在,跳转404
        if (!array_key_exists($qpth_, self::$p_list))
          self::to404();
    
        // 处理查询字符串,把它解析成$_GET的样子
        self::$get = array();
        if ($qpos_ !== false) {
          $ar_ = explode('&', self::$queryString);
          foreach ($ar_ as $value_) {
            $pr_ = explode('=', $value_);
            self::$get[$pr_[0]] = $pr_[1];
          }
        }
    
        // 直接调用API
        include(self::$p_list[$qpth_]);
      }
    
      static public function to404() {
        header('HTTP/1.0 404 Not Found');
    
        // 支持自定义404页面
        if (array_key_exists('404', self::$p_list))
          include(self::$p_list['404']);
        exit;
      }
    }

    最后 index.php 里面用 add 把页面啥的定义好,再一个 despatch 就完事了。

    <?php
    // index.php
    // 加载模块
    include_once('rRouter.php');
    
    // 你想把路径和哪个php页面相关联?写就是了
    rRouter::add('picture', 'pic.php');
    rRouter::add('audio', 'au.php');
    rRouter::add('link', 'lk.php');
    
    // 最后开始路由分发
    rRouter::despatch();

    最后

    其实把路由分发模块做好了,就可以拿去到处用了……

    写了那么多,感觉更多地是在谈路由分发呢……

    路由分发能做的,地址重写也可以做,但是地址重写要修改 rewrite 文件,可能需要重启网站服务才能生效(?),路由分发可以有更大的自由度,当然注意一下 BUG 就行了。