Rails 前置必修课:一次讲透 HTTP、REST、MVC、Cookie 与认证授权的 Web 基础
Rails 前置必修课一次讲透 HTTP、REST、MVC、Cookie 与认证授权的 Web 基础【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum这篇技术指南是 The Odin Project 课程本仓库为 curriculum 开源课程仓库中进入 Ruby on Rails 学习前的Web 复习课对应文档为 web_refresher.md。在动手安装 Rails、创建第一个应用之前你需要先补齐 Web 底层机制HTTP 请求与响应、REST 的 7 种资源操作、URL 的组成、MVC 架构、API 是什么以及 Cookie/Session/认证/授权如何协同工作。读完本文你将能看懂浏览器与服务器之间一次完整对话的每个环节并理解 Rails 之所以按特定方式组织代码的根本原因。为什么要先复习 Web 基础要真正理解 Rails 是如何工作的必须先对 Web 的内脏有一个扎实的基础。你在之前的课程如 HTML/CSS、JavaScript 部分已经接触过其中一部分内容如果已经学过本仓库的 Ruby 课程这部分可以快速浏览。但这次与以往不同的是接下来的项目会让你真正动手发起真实的 Web 请求亲手观察 HTTP 协议在浏览器与服务器之间如何流动。本课的学习目标Lesson overview如下HTTP 的基础知识。最常用的 4 种 HTTP 动词verb。Rails 的 7 条 RESTful 路由。URL 的各个组成部分。MVC 的基础知识。API 是什么。什么是 Cookie 与 Session。认证authentication与授权authorization的区别。HTTP浏览器与服务器之间的一次问与答HTTPHyperText Transfer Protocol本质上是浏览器与服务器之间组织请求—响应对话的一种方式。严格来说它甚至算不上对话因为 HTTP 是**无状态stateless**的——每一次请求之间彼此独立协议只是规定了这一小段问与答应该如何发生。一次 HTTP 交互有两大关键组成部分Header请求头/响应头包含关于请求或响应本身的元数据meta data例如要发送或返回给哪个网站、响应的状态码是什么。Body请求体/响应体请求体可以包含表单提交的数据、Cookie 或认证令牌authentication token响应体则通常包含你试图访问的 HTML 页面。4 个主要 HTTP 动词每一次请求都会使用以下四种动词之一动词语义典型用途GET获取请求一个页面或资源不改变服务器状态POST提交/创建提交表单数据在服务器上创建资源PUT更新提交数据以整体更新已有资源DELETE删除请求删除指定资源如今你在实际网络流量中几乎只会看到 GET 和 POST 请求即使是想删除某样东西很多网站也会用 POST 来伪装但理解四种动词之间的差异至关重要——这正是 Rails 路由系统判别请求去向的核心依据详见下文 REST 部分与 Rails 路由详解。动手实践建议打开浏览器的开发者工具切换到 Network网络面板访问任意网站并刷新页面观察每个请求的 method、status code、request headers 与 response body你就能直观看到上述概念在真实流量中的样子。这也是真实发起 Web 请求最简单的方式。REST把资源操作收敛为 7 种标准动作RESTRepresentational State Transfer表现层状态转移是一个你会在 Rails 学习中反复遇到的概念因为它是非常强大的建模思想。它的核心主张是针对某个单一资源resource通过 Web 你通常只想做 7 种类型的事情而这 7 种事情可以通过组合上述 HTTP 动词来完成。这里的资源通常指你数据库中的东西或一个数据模型例如一篇博客的 Post 模型#操作HTTP 动词 路径对应的 Rails 控制器动作1获取全部帖子GET/postsindex2获取某一篇帖子GET/posts/:idshow3查看新建帖子页面GET/posts/newnew4把新帖数据提交给服务器创建POST/postscreate5查看编辑帖子页面GET/posts/:id/editedit6把编辑后的数据提交给服务器更新PUT或 PATCH/posts/:idupdate7删除某篇帖子DELETE/posts/:iddestroy表中的高亮词index/show/new/create/edit/update/destroy正是Rails 标准的控制器动作controller action为什么 REST 如此重要它给了你组织资源的清晰思路REST 是建模请求的标准方式也应当是你处理请求的唯一方式。例如你不应该用 GET 请求来提交编辑帖子的数据——那应该是 POST或 PUT。它是检验数据模型设计的一把尺子如果你很难想象上述 7 种场景或其中一部分如何套用到你准备创建在数据库中的资源上那么你可能需要重新思考数据结构的组织方式。Rails 天生遵循这套约定只要你的请求符合这些约定浏览器发来的请求就能顺畅地被路由到 Rails 内部对应的动作上开发体验会非常轻松。这看起来可能过于简单但当数据模型变得复杂时回归 RESTful 思维往往能帮你把纠缠不清的逻辑重新理出头绪。Rails 中一条龙声明 7 条路由Rails 知道你想反复使用这 7 个动作因此提供了resources这个便捷方法——在 config/routes.rb 对应的路由讲解 中可以看到你只需一行代码就能替代上面七行# config/routes.rb resources :posts这一行 Ruby 方法本质上就是展开成那 7 条 RESTful 路由毫无魔法。你还可以用only或except精确控制生成哪些路由resources :posts, only: [:index, :show] resources :users, except: [:index]运行rails routes可以查看应用当前所有可用路由例如edit_post GET /posts/:id/edit(.:format) posts#edit注意:id前面的冒号它告诉 Rails这里匹配任意内容并把它作为id存入params哈希。因此/posts/1和/posts/5都会进入PostsController#show只是params[:id]不同。Rails 还会自动为每条路由生成以_path/_url结尾的辅助方法如edit_post_path(3)生成/posts/3/edit方便你在视图中用link_to生成链接而不必硬编码 URL。URL拆开看每一个组成部分你可能觉得自己知道 URL 里有什么但你能分清哪个部分是 host主机、protocol/scheme协议、parameters参数、path路径吗以如下 URL 为例https://www.google.com/search?qwhatisaurl问题答案Path路径是什么/searchParameter参数部分是什么qwhatisaurlTop Level Domain顶级域名是什么comProtocol协议是什么https理解这些组成部分后你就能轻松使用 Ruby 的库来构建自己的 URL 并发起请求。在 Rails 中你也会反复与路径和参数打交道——路由里的:id动态段、params哈希、查询字符串等本质都源于 URL 的这些基本结构。MVCRails 应用的组织骨架MVCModel-View-Controller的核心就是组织而 Rails 的一切都围绕 MVC 展开。当你新建一个 Rails 项目时会得到一大堆文件夹和文件app目录下看似数量惊人但它们被高度组织化明确用于分离 Model模型、View视图和 Controller控制器。MVC 的意义在于Web 应用的功能可以被拆分为相对独立的部分每一部分对应一个 Ruby 类。这对开发者非常友好——当你需要调整某一块代码或修复 bug 时你知道该改哪个文件、文件在哪里。一次请求穿过 MVC 的完整路径当一个来自浏览器的请求进入你的应用最基础的流程是路由Router判断该把请求交给哪个控制器例如博客应用的 PostsController。控制器Controller向模型如 Post model索要数据并向它提出其他难题。控制器再把所需数据交给视图View例如index.html.erb——视图本质上是等待这些变量的 HTML 模板。当视图被填满所需数据比如当前用户的姓名后渲染结果被送回最初发起请求的客户端。完成一个贴切的非正式比喻模型是后台房间里的超级聪明怪才控制器是八面玲珑的社交中间人它跟所有人说话但自己不做繁重计算繁重活都交给模型视图则负责打扮漂亮等着控制器为它搭配好行头。在 Rails 路由与控制器 中可以看到路由与控制器动作一一对应例如resources :posts生成的 7 条路由对应PostsController中index、show、new、create、edit、update、destroy7 个方法每个方法内部再与 Model 交互、渲染对应 View。API应用与应用之间对话的侧门当你的计算机或你编程的服务器想向另一个网站请求数据时它不会去浏览器里点来点去而是直接通过那个网站的APIApplication Programming Interface索要数据。API 本质就是一个接口interface我们的浏览器从前门进入展示 Facebook 的一大堆信息而我们的 Web 服务器则从侧门进入获取同样的数据——更快、更直接。你想把 Google Maps 的数据显示在网页上按照其 API 文档规定的规则调用 API 即可。几乎所有大型网站都会把部分数据通过 API 开放出来用 Rails 构建自己的 API 也相当容易。并非所有 API 都是基于 Web 的但大量 API 使用同样的 HTTP 格式专门用于在服务之间传递数据。事实上Rails 的各个组件之间正是通过 HTTP 相互通信串起来的。在 Rails 中构建 API 并不神秘你只需让控制器除了响应普通 Web 请求之外或取而代之还能响应其他服务器发来的请求并指定返回的内容通常不再是 HTML 视图。相关实现细节可以参考 构建你自己的 API利用respond_to方法同一个控制器动作可以按请求格式返回 HTML、JSON 或 XMLclass UsersController ApplicationController def index users User.all respond_to do |format| format.html # index.html.erb format.xml { render :xml users } format.json { render :json users } end end endrender :json会对对象调用to_json把 Ruby 对象序列化为可传输的 JSON 字符串。这就是你的 Rails 应用其实已经是一个 API——浏览器本质上也是在向你的应用发起 API 请求只不过渲染 HTML 太常见我们把它当成了默认响应类型。Cookie让无状态的 HTTP记住你是谁你已经听说过 Cookie。Cookie 是网站用来在多次请求之间记住你是谁的小数据块。还记得吗——每一个 HTTP 请求都是完全独立的也就是说当你访问某个网站首页后又点击链接进入 About 页时Web 服务器本应把你当成一个全新的用户……除非它给了你 Cookie而它几乎一定给了。Cookie 是你的浏览器在每次向某网站发起请求时自动附带发送过去的一小块数据。从 Web 服务器的视角看Cookie 让它能把你识别为之前一系列请求的同一个发起者从而保留了你的session会话状态。动手实验打开你常访问的网站调出开发者工具。在 Chrome 中点击 Application 标签页再点击左侧菜单的 Cookies你会看到一个个 name-value 对。通常其中会有一个user_session或token之类的变量值是一串难以辨认的字符。SessionCookie 支持的连续会话Cookie 之所以重要是因为它让你在访问网站期间拥有一个单一的、连续的会话你只需要登录一次而不必为每一个请求都重新登录这正是 90 年代末某些坏掉的网站会带给你的体验。你的浏览器会把某个网站设置的所有 Cookie 连同正常请求一起提交服务器利用这些字符串来判断你是谁、是否已登录、你的偏好设置比如浏览偏好等等。这也是为什么当你清除浏览器历史中的 Cookie 后一切似乎都被重置回默认状态。另外某些广告之所以能跟着你从一个网站跑到另一个网站是因为它们的另一个名字叫跟踪 Cookietracking cookies。Rails 中的 cookies 与 session在 Session、Cookie 与认证 一课中可以看到 Rails 对这两者的完整封装。Rails 提供两个长得像哈希的对象# 设置一个 Cookie会作为独立 Cookie 存在用户浏览器中 cookies[:hair-color] blonde # 删除一个 Cookie cookies.delete(:hair-color) # 设置过期时间 cookies[:name] { value: cookies YUM, expires: Time.now 3600 } # 设置会话值session session[:current_user_id] user.id # 读取会话值 session[:other_variable_key] # 重置整个会话 reset_session两者的区别很关键cookies每个键值对作为独立的 Cookie 存储在用户浏览器中直到过期。适合存储站点显示偏好等非敏感数据不要在里面存放需要安全保护或跨浏览器会话持久的数据——用户太容易清空缓存或偷窃/篡改不安全的 Cookie。session整个会话哈希被 Rails 放入一个安全、防篡改的 Cookie 中浏览器关闭即过期。Rails 内部通过这个特殊 Cookie 来识别用户会话信息。注意两个使用限制session与cookies并不是真正的哈希Rails 只是让它们行为像哈希二者都有约 4KB 的大小限制足够常规使用但不要把它们当成数据库的替代品。Rails 还提供flash哈希它只在一次请求到下一次请求之间存活适合在redirect_to之后把注册成功之类的提示消息传给视图因为重定向会发起全新请求实例变量会全部丢失。当视图读取后Rails 会自动清除它同请求内立即渲染时则应使用flash.now。认证Authentication确认用户是谁在服务器端你经常要与 Cookie 和会话变量打交道其中最主要的用途之一就是判断用户是谁——即认证authentication。基本流程是取出用户发来的 Cookie → 用它去数据库中找到该用户 →如果用户存在为该用户渲染定制化的网页。理论上很简单但安全性方面的某些细节相当棘手。幸运的是有现成的Devisegem 帮你处理这一切本课程稍后会先让你亲手实现自己的认证系统再学习用 Devise 接手繁重工作。密码不能明文存储不要自己造认证轮子已经有久经实战考验的成熟方案但有几个原则值得了解。首先绝不以明文形式在数据库中存储密码——而是存储加密后的密码摘要password digest。用户通过登录表单提交密码时你把它也转换成摘要形式再与数据库里之前存储的摘要比对一致则登录成功。摘要是单向加密从密码字符串生成摘要很容易但从摘要反推出原始密码极其困难。破解大量摘要最有效的方式不过是大规模猜—试造一张巨长的可能密码表全部转成摘要再逐一对撞。Rails 为此内置了has_secure_password方法放进 User 模型即可获得大量现成功能模型接受password和password_confirmation属性并不真正持久化到数据库由该方法拦截并转换为密码摘要。配合authenticate方法可以校验凭据是否正确。登录成功后把用户 ID 存入session变量即可在后续请求中确认其身份。若想让用户被记住登录表单上常见的 remember me 复选框则需要在 Users 表增加一列存储加密的remember_token并把未加密的 token 以永久 Cookiecookies.permanent[:remember_token]写入用户浏览器每次请求时比对数据库中的加密版本最佳实践是每次重新登录时重置 token。授权Authorization限制用户能做什么授权authorization是与认证相伴的概念认证确定用户是谁而授权则根据其权限级别限制其能看什么。最常见的两种情况一是未登录的游客与已登录用户的区分二是普通用户与拥有特殊权限的管理员的区分。在服务器端你需要编写或使用一些限制方法根据当前用户是谁或请求者是否已登录来限制对某些动作的访问。Rails 中实现这一点的标准工具是控制器过滤器controller filters# app/controllers/users_controller.rb before_action :require_login before_action :do_something_cool private def require_login if current_user.logged_in? # 允许用户执行其想要的动作 else redirect_to login_path end endbefore_action接收一个方法名符号在控制器执行任何其他代码之前运行若回调中发生渲染或重定向该请求以及排在它之后的回调都会被取消。可以用only/except选项限定仅对特定动作生效如before_action :require_login, only: [:edit, :update]。过滤器会被继承若想对所有控制器生效把它放进app/controllers/application_controller.rb。Devise 也提供了现成的辅助方法如判断是否有用户登录、当前用户是谁来配合这类授权检查。认证与授权相辅相成先认证某人以确认其身份再检查其是否有权查看页面或执行动作。结语后面的课程会深入这些主题但现在把它们放在请求如何发生的语境下理解非常值得认证系统让你建立会话session会话通过 Cookie 跨请求保留用户状态如登录状态并帮助你判断该用户是否有权authorized做某件事。这些机制在原本彼此独立的 HTTP 请求之上叠加了两层关键的能力——记忆与权限。自测学完你应该能回答从客户端发往服务器的 HTTP 消息叫什么从服务器发往客户端呢哪条 HTTP 消息包含状态码status code哪条包含动作动词action verb在 URL 的路径之后追加的额外信息叫什么MVC 代表什么什么是 API为什么需要 Cookie 来维持你的 Session认证authentication与授权authorization的区别是什么如果这些问题无法立即回答建议回到上文对应小节复习。相关进阶内容可继续阅读仓库中的 Rails 路由详解、Session、Cookie 与认证 以及 构建你自己的 API 等后续课程文档。【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考