Pascal中的网站开发(后端)

在本文中,我将讨论为什么,为什么以及如何开始在Pascal上创建站点:Delphi / FPC。
“ Pascal网站”可能与以下内容相关:

writeln('Content-type: text/html');

但是不,一切都更加有趣!但是,可以在GitHub上获得真实站点(几乎所有站点)的源代码。

做什么的?


总的来说,我从来不是专业的网络开发人员-我制作游戏。游戏,尤其是在线游戏,需要网站。因此,碰巧我开始为我的游戏制作更多的网站。在Perl上使用CGI-在2000年代初期/中期很流行。一切都很好,直到出现问题为止。

2013年,我们开始举办Spectromancer游戏的在线锦标赛,为此,我在该游戏的网站上创建了一个锦标赛页面,其中显示了与谁一起玩的人,最新结果等。在比赛开始时,玩家页面已更新,并且...未加载。人们按下F5键,进一步加剧了这个问题。事实证明,对于CGI脚本,每秒甚至有4-5个请求,作为一个单独的Perl进程运行,大大降低了服务器的速度,并且每秒超过10个请求使它完全不可访问。

压力测试是在排练比赛期间进行的,这很不错:稍后,我已经将更新的静态页面用于比赛。

为什么?


因此,当需要将这个站点制作成新游戏时,问题就出现了-什么?不能在Perl上使用Brake CGI。Perl中的FastCGI?我无法想象如何在Perl中编写和调试多线程程序,我在使用普通脚本时遇到了很多问题。Node.js?如果不是因为对JS的敌意,这可能是最好的选择。而且由于游戏本身及其服务器是用Pascal编写的(实际上是Delphi,但FPC也是不错的),所以产生了这个主意-我们应该用相同的语言来制作网站吗?这将简化与游戏服务器的集成。“尝试不是折磨!” 我想了,决定尝试一下。

怎么样?


我选择了SimpleCGI(SCGI)作为接口:它比FastCGI简单一些,后者的优点对我来说无关紧要-不需要将后端分发到不同的服务器,所有的东西都在同一服务器上运行。因此,该任务归结为某种SCGI框架的开发,该框架处理来自服务器的请求并响应一些空白模板而生成HTML页面。结果就是这样的模块框架它由以下部分组成:

  • 主循环:接受传入的连接,读取请求并将其放入队列进行处理。将对已处理请求的现成响应写入连接套接字并关闭它们。
  • (N ): , . worker' — .
  • : HTML- ( ) . .
  • : ( CGI.pm Perl). , ..


Perl脚本的一个非常方便的功能是,对网站进行少量更改非常容易:只需编辑脚本代码即可。无需编译,部署。当然,pascal是一种编译后的语言,它不会那样工作,但是我仍然希望能够在不重新启动过程的情况下尽可能进行更改。因此,我试图使模板系统足够灵活。

她那样工作。模板文件位于“ templates”文件夹中:它们在流程启动时加载,并且在更改时重新加载-这样,您可以更改动态内容而无需重新启动流程。每个文件可以具有一个或多个模板。它们一起形成模板的字典(或散列):{“ name”->“ value”}。这是模板的静态字典-所有请求通用,并且其内容保持不变(直到文件内容更改)。还有一个-动态字典,它为每个请求创建为空,并用例如数据库中的动态数据处理程序填充。结合静态和动态数据,形成最终结果。

模板声明示例:

#NEWSFEED_ITEM:
<div class=NewsHeader>
 <a href='/$LANG_LC/forum/thread/$NEWS_ID'><IF_NEWS_PINNED>[TOP]  </IF_NEWS_PINNED>$NEWS_DATE   $NEWS_TITLE</a>
</div>
<div class=NewsText>$NEWS_TEXT
 <div align=right>
  <a href='/$LANG_LC/forum/thread/$NEWS_ID'>$COMMENTS</a>
 </div>
</div>

这是一个静态模板,用于以名称NEWSFEED_ITEM的名称写在新闻提要中,其中包含其他几个模板,例如NEWS_TEXT-一个动态模板,其中包含从数据库下载的新闻文本。转换是将$ TEMPLATE_NAME形式的所有子字符串递归替换为该模板的值。

在这里,您还会注意到用于条件翻译的伪标记:<IF_TEMPLATE_NAME>-在翻译期间,根据指定模板的值,将删除此类标记,并保留或删除其内容。我特别选择了这种格式的条件-以HTML标记的形式,以便在文本编辑器中进行编辑时,语法突出显示有效并且很容易看到配对的标记。

使用此模板的提要生成代码如下所示:


    result:='';
    //       NEWSFEED_ITEM      result
    for i:=0 to n-1 do begin
      id:=StrToIntDef(sa[i*c],0);
      title:=sa[i*c+1];
      cnt:=StrToIntDef(sa[i*c+2],1)-1;
      flags:=StrToIntDef(sa[i*c+3],0);
      //     
      db.Query('SELECT msg,created FROM messages WHERE topic=%d ORDER BY id LIMIT 1', 
        [id]);
      if db.lastErrorCode<>0 then continue;
      text:=db.Next;
      date:=db.NextDate;
      //    ( temp)
      temp.Put('NEWS_ID',id,true);
      temp.Put('NEWS_DATE',FormatDate(date,true),true);
      temp.Put('NEWS_TITLE',title,true);
      temp.Put('NEWS_PINNED',flags and 4>0,true);
      comLink:='$LNK_READ_MORE | ';
      if cnt>0 then comLink:=comLink+inttostr(cnt)+' $LNK_COMMENTS'
        else comLink:=comLink+'$LNK_LEAVE_COMMENT';
      temp.Put('NEWS_TEXT',text,true);
      temp.Put('COMMENTS',comLink,true);
      //   
      result:=result+BuildTemplate('#NEWSFEED_ITEM');
    end;

本土化


模板也方便用于本地化。为此,请使用全局(在请求的上下文中)clientLang变量。它的工作原理是这样的:如果请求处理程序发现客户端需要俄语页面,则他在clientLang中写入值“ RU”,然后模板翻译器在文本中找到$ TEMPLATE_NAME,始终尝试首先应用$ TEMPLATE_NAME_RU。因此,对于本地化,仅需要每个带有文本的模板为另一种语言创建其版本:

#TITLE_NEWS:News
#TITLE_NEWS_RU:

使用框架的例子


简单的站点代码示例:

program website;
uses SysUtils, SCGI;

//    
function IndexPage:AnsiString; stdcall;
 begin
   result:=FormatHeaders('text/html')+BuildTemplate('#INDEX.HTM');
 end;

begin
 SetCurrentDir(ExtractFileDir(ParamStr(0)));
 SCGI.Initialize; //  
 AddHandler('/',IndexPage); //     '/'
 SCGI.RunServer; //      
end.


在2015年底创建真实网站astralheroes.com的过程中编写了描述的框架通常情况下,第一个煎饼有点块状-代码变得有些混乱和混乱,下一个站点正在变得更好。但是,我对过程和结果感到满意:该站点运行良好,易于调试和更新。

发现:

  • 我期望与紧凑的Perl相比,站点代码非常膨胀,但是没有-用Pascal编写的相同功能仅需要Perl的两倍。但是看起来更清楚了。
  • ! Perl — , - 100 , , . - - — . Delphi .
  • Perl. -, , , . -, Perl, , .
  • : , , . .
  • . , , ( ), , . , , — . .

    , . — . , :



    , — . , .

?


GitHub上的源代码:github.com/Cooler2/ApusEngineExamples

注意,存储库中有一个子模块,因此最好使用“ --recursive参数进行克隆

该站点项目位于文件中:“ AH-Website \ Backend \ src \ website.dpr”

这不是当前站点的完整副本:很明显,我无法使用播放器的数据发布数据库的内容,我也不会发布CGI脚本,因为它们与主题无关。但是,该项目正在组装,启动和工作中,充分展示了框架的工作。

由于我在Patreon上获得的支持,使得站点代码及其使用的引擎代码的发布成为可能我感谢所有支持我并敦促您加入的人们-未来还有很多有趣的事情:)

谢谢您的关注!

All Articles