导读:本期聚焦于永濑创作的《基于Camping::Controllers的请求路由:RESTful动作与过滤器该如何使用?》,敬请观看详情。Camping是一个体积极小的Ruby Web框架,它的路由系统核心就藏在Camping::Controllers模块里。本文围绕R路由匹配、RESTful风格动作定义以及before过滤器三个关键点展开,先讲清楚Controller类与R路由块的对应关系,再演示GET、POST等动作如何接收参数,最后说明过滤器在鉴权、日志场景中的用法。文中配有可运行的代码示例,也会对比路由优先级与常见踩坑点,适合想在轻量项目中快速搭建接口的开发者参考。掌握这些内容后,你可以用两百行以内的代码构建一套结构清晰的小型Web服务。

Camping是Ruby世界里出了名的“小而美”框架,整个框架源码不到两千行,却把MVC的核心思路都装了进去。它的路由设计比较特别:不是像Rails那样用独立的routes文件声明式地写路由表,而是把路由信息直接嵌在Controller类的继承结构里。这套机制全部由Camping::Controllers模块提供,理解了它,基本就理解了Camping的一半。

基于Camping::Controllers的请求路由:RESTful动作与过滤器该如何使用?

一、Controller与R路由块的基本原理

在Camping中,每一个Controller类对应一组URL。路由匹配靠的是类内部的R路由块,写法是R '/路径/:参数'这种形式。Camping启动时会扫描所有Controller,把R块里的路径模式编译成正则表达式,请求进来后按定义顺序逐个匹配,命中哪个Controller就实例化哪个。

下面是一个最简单的例子,包含两个Controller,分别处理首页和文章详情页:

module Blog::Controllers
  class Index
    # 匹配根路径 /
    R '/'
    def get
      "欢迎来到我的博客"
    end
  end

  class Show
    # 匹配 /posts/1、/posts/abc 这类路径
    R '/posts/(\d+)'
    def get(id)
      "这是第 #{id} 篇文章"
    end
  end
end

注意路径里那个(\d+),它是一个正则捕获组,匹配到的内容会作为参数传给对应的动作方法,所以get方法需要声明一个id形参来接收。这一点和Rails的:id符号参数不同,Camping底层就是纯正则,捕获组按顺序对应方法参数,理解了这一点写路由就不会混乱。

还有一个容易忽略的细节:路由匹配的优先级与类定义顺序无关,而与模块内类名的字母排序有关。如果你的两个路由模式有重叠,比如一个匹配/posts/(\d+),另一个匹配/posts/new,一定要想清楚哪一个类名排在前面,否则可能出现请求被意外接管的情况。这是Camping最经典的坑之一。

二、RESTful动作的定义与参数处理

Camping对RESTful的支持非常直接:Controller里的public方法名就是HTTP方法名。get处理GET请求,post处理POST请求,putdelete同理。如果请求方法找不到对应方法,Camping会尝试调用method_missing相关的默认逻辑,最终返回405状态码。

表单参数和URL参数的接收方式也很朴素,全部通过input这个HashLike对象:

module Blog::Controllers
  class Create
    R '/posts'
    def post
      # 接收表单或JSON提交的参数
      title = input.title
      content = input.content
      Post.create(title: title, content: content)
      redirect Index
    end

    def get
      # GET /posts 返回文章列表JSON
      @posts = Post.all
      render :list
    end
  end

  class Delete
    R '/posts/(\d+)'
    def delete(id)
      Post.find(id).destroy
      redirect Index
    end
  end
end

代码里的redirect Index也是Camping的特色写法,直接传Controller类就能跳转到该类的默认路由,不用手写URL字符串,重构路径时不容易漏改。

对于PUT和DELETE请求,由于HTML表单原生不支持,可以通过带_method隐藏字段的POST来模拟,Camping会自动识别并转发到对应动作。另外,环境相关信息可以从envrequest中拿到,比如@env['HTTP_USER_AGENT'],写接口日志或做UA判断时用得上。

三、过滤器的编写与执行时机

过滤器在Camping里体现为几个约定方法:initializeservicerespond。整个请求生命周期是:先创建Controller实例,调用initialize做初始化,接着调用service做路由分发,service内部调用具体的动作方法,最后调用respond包装输出。覆写这三个方法中的任意一个,就相当于插入了一个过滤器。

不过直接在每个Controller里覆写太啰嗦,Camping提供了before方法,可以配合一个基类实现全局拦截:

module Blog::Controllers
  # 所有Controller的公共基类
  class Base < R
    def service(*a)
      # 请求日志过滤器
      start = Time.now
      r = super(*a)
      log.info "请求 #{@env['PATH_INFO']} 耗时 #{Time.now - start}"
      r
    end
  end

  class Admin < Base
    R '/admin'
    # 鉴权过滤器
    def before
      # 也可以在Base中统一处理
      @user = User.find(cookie.user_id) rescue nil
      unless @user && @user.admin?
        redirect '/login'
      end
    end

    def get
      "管理后台,欢迎 #{@user.name}"
    end
  end
end

上面代码用了两层过滤:基类的service负责打点日志,子类的before负责登录校验。注意service里必须调用super并返回其结果,否则请求会在这里被“吞掉”,直接返回空响应。这类bug很隐蔽,页面不报错只是空白,排查时优先检查过滤器有没有正确传递返回值。

过滤器的执行顺序是固定:initialize、before、具体动作、respond。如果before里调用了redirect或throw,动作方法不会执行。利用这个特性可以把权限校验全部收口到过滤器层,让动作方法保持纯粹的业务逻辑。

四、实战中的一些经验总结

路由数量多了以后,建议按资源拆分Controller,一个资源一个类,类名用资源名单数形式,方便推断排序优先级。共享逻辑抽到Base类,避免过滤器代码到处复制。

调试路由时可以在项目根目录跑camping blog.rb启动服务,配合终端输出的请求日志快速确认请求到底进了哪个Controller。如果发现404,先检查R块的正则是否真的能匹配目标路径,用"/posts/123".match(%r{/posts/(\d+)})这样的单行代码在irb里验证正则,比反复重启服务快得多。

最后提醒一点,Camping的会话和Cookie默认通过cookiesstate方法访问,state存在签名Cookie里,适合放登录态这类轻量数据,不要往里塞大对象。把路由、动作、过滤器这三块吃透,用Camping搭一个小型API服务或工具页面,代码量往往不到Rails项目的十分之一,维护起来相当轻松。

Camping框架请求路由RESTful动作修改时间:2026-09-03 15:11:14

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260903/49638.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。