Bearweb网站架构-流程

Bearweb是一个为个人网站与小型组织设计的轻量级的数据库驱动PHP网站架构。Bearweb使用简单的数据库与代码结构,致力于降低网站维护难度与成本。

--by Captdam @ Jul 2, 2023

Bearweb是一个为个人网站与小型组织设计的轻量级的数据库驱动PHP网站架构。Bearweb使用简单的数据库与代码结构,致力于降低网站维护难度与成本。

这个页面简单介绍一下Bearweb的特点与开发过程。

关于HTTP

首先,作为背景,简单地来说一说HTTP。浏览网页就是客户端(浏览器)向服务器发送对资源的请求。当打开一个页面,例如一个URL为http://bearweb.com/bearweb-zh的页面,实际就是客户端(浏览器)在向服务器请求下载http://bearweb.com/bearweb-zh所储存的资源。如果浏览器下载这个资源后发现这是一个网页页面(HTML),那么浏览器就会渲染这个页面;如果下载的是多媒体资源,如图片,那么就显示出来;如果是js脚本,那么就执行。

站在服务器的角度来看,每一次访问就是客户端向服务器发送一个文件,文件内包含了需要请求的资源信息(URL)和客户端信息(cookie,浏览器型号……)。对于POST和PUT类型的请求,客户端发送的文件还包含了要上传的数据、文件。服务器在处理完客户端的请求后,会将处理结果作为一个文件返回给客户端。这个返回的文件可以是一个网页,可以是一个多媒体文件,也可以是自定义的数据文件或者二进制文件。

处理流程

Bearweb是一个基于PHP的网站架构。当服务器接收到请求后,服务器接口(例如Apache)就会将这个请求转发给指定的PHP脚本。对于Bearweb,所有的请求都会被发送给index.php。这个脚本只是一个入口,它负责配置了一些服务器设置,例如数据库路径,模板路径。实际的处理,则会交给bearweb.class.php进行处理。

bearweb.class.php中包括了核心架构的三个组件:

首先由这三个核心架构组件对请求进行处理。概括来讲,这三个组件将会从数据库中读取请求的资源,记录当前请求,并且判断当前会话的用户是否有该资源的权限。如果用户没有权限,那么就返回一个错误;如果有,那么就进入下一步。

网站的功能多种多样。每一种资源都由不同的处理方式,Bearweb的数据库中只保存了资源的数据,但是如何展示这个资源的方式却多种多样。例如,一篇博客应该使用博客界面专用的header与footer,海报页面应该不包含header与footer,图片资源则应该完全不适用HTML界面而是直接输出。而且,网站功能也不仅仅是提供某项资源的下载。例如,作者可以向网站上传博客,因此网站需要支持上传。再例如用户登录组织网站,这就需要修改上面提到的会话的用户。将所有功能都写入Bearweb的核心架构显然不是什么好想法。Bearweb的核心架构只提供对请求的基本处理,而具体的处理则交给处理模板。

Bearweb支持开发者自定义处理模板(虽然也可以直接修改bearweb.class.php中核心架构的代码但是这就太绿皮了!),默认储存于template文件夹。处理模板包含三大类:

在运行处理模板后,Bearweb就完成了对该请求的处理。Bearweb或是返回用户请求的资源,或是按照用户的请对服务器上一个资源进行处理,或是在有任何错误的情况下返回一个自定义的错误页面与错误代码。

核心架构

Bearweb有三大核心架构组件:站点组件、会话组件、用户组件。每一个组件都有自己的数据库。除了站点组件是必要组件外,另外两个组件都可以被禁用(Bearweb将会在禁用或出错的情况下使用默认值)。

首先,Bearweb将需要初始化三大组件(连接组件数据库)。如果站点组件Bearweb_Site初始化失败,Bearweb将会使用“错误页面”的模板。如果会话组件Bearweb_Session或用户组件Bearweb_User初始化出错,或是没有定义数据库路径,Bearweb将会使用默认值(不记录请求,不建立会话,默认用户为游客)。除了一些API(例如上传文件),Bearweb将不会报错,这里使用了“Fail-safe的想法”,因为大部分情况下非必要组件不应该影响网站功能。例如网站磁盘空间不足的情况下,虽然不能再记录更多的会话历史,但是不应该影响用户正常浏览网站,影响网站在线率。

站点组件 - Bearweb_Site

Bearweb定义,每一个资源应该都有一个URL,同一个URL不能用于不同的资源(API每一个URL为一个endpoint)。因此,站点组件的数据库储存了网站上所有的URL所对应的资源。例如,http://bearweb.com/bearweb-zh是一个博客文章,那么站点组件的数据库储下URL键为bearweb-zh的记录就包括了这一篇博客的资源内容(标题、关键字、内容、修改时间……)与处理逻辑(处理模板、资源状态、所有者)。

站点组件的功能就是将这些数据从数据库里读出来,并将数据从数据库内的储存格式转化为处理模板使用的格式(例如,数组使用文本结构储存,时间使用timestamp int结构储存)。此外,在处理API请求时,站点组件还有反向将资源数据转化为储存格式并写入数据库的功能。

除此之外,站点组件还可以根据资源的状态决定是否进行重定向,亦或是根据会话组件提供的信息判断当前客户是否可以使用该资源。

会话组件 - Bearweb_Session

Session: 当一个新用户首次访问站点,会话组件就会这次会话此建立一个在会话数据库Session表中随机唯一的会话ID。该用户接下来的请求都会使用同一会话ID,并且每次都会更新这个会话ID的使用时间。会话ID是通过cookie的方式储存在客户端的,包括一个用户端JS脚本可见的SessionID和一个JS脚本不可见的SessionKey(用于防止JS注入窃取会话)。如果这个SessionsID过期,或是客户端与服务端的SessionKay与SessionID不匹配,那么会话组件将认为用户的会话ID不合法,并会重新生成一个会话ID。

Request: 每当用户发出一个请求,会话组件就会为这次请求建立一个在对话数据库Request表中随机唯一的请求ID,并记录本次请求的会话ID,用户IP,内容摘要。

如果用户禁用了cookie,那么会话组件将不会从客户端接收到将SessionID与SessionKay。因此,会话组件将认为用户是第一次访问网站,因此会在每一个请求都生成一个新的会话ID;如果会话组件Bearweb_Session被禁用或是出错,那么将不会生成会话ID与请求ID,并使用默认值。这两种情况下,都将认为用户为游客。

会话组件与用户隐私

当代互联网的一大问题就是用户隐私问题。会话组件无疑能用于追踪用户在Bearweb站点的行为,例如用户在何时访问了Bearweb,访问了哪些页面。因为Session ID是基于cookie的,因此用户可以通过禁用cookie的方式避免被会话组件追踪。但是,相应的,也就不能使用基于会话的功能(例如无法登录,永远为游客。对于某些网站,用户需要首先访问网站获得token才能访问多媒体资源,这种情况下将永远无法加载这些资源)。基于cookie的会话控制是网站开发的常用方法,因为Bearweb需要进行用户访问控制,所以Bearweb需要使用cookie以进行会话控制。

除此之外,用户的IP也将被记录。用户IP是包含在任何网络包中的数据,IP记录了包裹的发送方与接收方,因此IP不可被禁用。当然,用户可以使用VPN,这样就只有VPN的IP被暴露而不是用户自己的IP。不过,VPN提供方还是能查看到用户的IP。

Bearweb只使用会话控制作为用户登录与访问管理。除非用户有登录并且用户组件有记录用户的信息,否则会话都是匿名的。

Side note:互联网不存在“无痕浏览”!浏览即下载,下载即访问。所谓“无痕”只是客户端没有记录,服务端与所有的路由节点都能留下记录。

用户组件 - Bearweb_User

用户组件用于记录用户的ID,用户名,密码,所在分组等信息。

用户组件建立在会话组件之上。会话组件记录了当前会话的用户,这个值将被会话组件用于从用户组件的数据库中读取该用户的信息。如果会话组件或是用户组件被禁用或出错,那么用户组件将使用默认用户(游客)。

用户组件记录了用户所在的组,这一信息被用于资源的访问控制。对于需要访问权限的资源,用户所在的组必须为资源开放的组中任一一个。

处理模板

处理模板用于定义该如何处理数据库里面的资源数据,并将处理完的数据返回给客户端。Bearweb的处理模板分为三个母模板:页面模板、对象模板、API模板。母模板下定义了子模版以决定更细节的处理流程。当然,为了增加网站功能性,用户也可以修改或加入自定义模板。

页面模板 - page

对于大部分网站来说,每一个页面的布局都是差不多的。不同的页面有不同的正文内容,但是页头与页尾是一模一样的。页面模板的目的就是包含这些对于所有页面来说都一模一样的部分(页头,页尾),这样就不需要为每一个页面都单独加入页头与页尾的HTML代码了。此外,当需要修改页面布局时,只需要修改页面模板,就可以对所有页面的布局同时进行修改,提高了网站页面的一致性。

页面模板将固定设定输出内容的mime typetext/html。页面模板将根据资源的创建时间与修改时间决定缓存策略。

对象模板 - object

对象模板用于输出站点的非网页资源,例如图片、JS脚本。当然,也可以使用对象模板输出不包含页面模板的页头与页尾的页面。

页面模板将根据站点模块提供的资源信息决定输出内容的mime type。站点模板将根据资源的创建时间与修改时间决定缓存策略。

API模板 - api

API模板用于定义站点的endpoint,作为客户端与服务端后台交互的接口。API模板是完全自定义的。