Golang开发的全功能单文件Web服务器

最新HTTP/2标准已经发布,是基于谷歌QUIC的技术升级而成。虽然标准已经发布,但是目前还鲜有应用支持,那么有没有方法进行技术尝鲜呢?答案是肯定的。本文虫虫给大家介绍一个Golang Web服务器应用Algernon,作为一个单文件的Golang应用内置了HTTP/2,Lua,Markdown,Pongo2,HyperApp,Amber,Sass(SCSS),GCSS,JSX,BoltDB的功能,支持 Redis,PostgreSQL,MariaDB / MySQL数据库。支持限速,插件,用户和权限等各种功能。所有这些都包含在一个自包含可执行文件中,麻雀虽小五脏俱全。

技术架构

使用Golang开发,后端数据库可以使用Bolt(内置),MySQL,PostgreSQL或Redis(推荐)。对各种功能支持总共使用了下面的类库:

permissions2用于处理用户和权限;gopher-lua用于解释和运行Lua;http2用于服务HTTP/2,QUIC用于服务QUIC;blackfriday用于Markdown渲染;amber用于Amber模板;Pongo2用于Pongo2模板;Sass(SCSS)和GCSS用于CSS预处理;logrus用于日志记录;goja-babel用于从JSX转换为JavaScript;tollbooth用于速率限制;pie用于插件支持;graceful用于优雅关闭。

设计思想

该项目源于用Markdown,Pongo2,Amber,HTML或JSX(+ React)等编写应用,并用CSS样式支持和设计。数据使用Lua脚本与Redis,BoltDB,PostgreSQL或MariaDB/MySQL链接操作。

Amber和GCSS是时下静态网站的最佳组合方式,与HTML和CSS相比,它允许更清晰的架构,减少内容重复,也很容易使用Lua提供数据,支持MVC架构对模型(M),控制器(C)和视图(V)的更好的分割。

Pongo2,Sass和Lua也是很好的一个选择,而且Pongo2比Amber更灵活。

Bolt是一个纯粹的key/value存储,使用Golang编写。Bolt无需预先安装设置数据库,内置在Algernon中使用。也支持广泛使用的数据库,比如MariaDB/MySQL和PostgreSQL。

Algernon以下文件进行特殊渲染和解析以下文件(后缀),按优先顺序排列:

index.lua是Lua代码,动态lua脚本处理。

index.html HTML默认页面。

index.md 渲染为HTML下的Markdown代码。

index.txt 纯文本文件。

index.pongo2,index.po2或index.tmpl渲染为HTML的Pongo2代码。

index.amber渲染为HTML的Amber代码。

index.hyper.js或index.hyper.jsx渲染为HTML的JSX + HyperApp代码

data.lua是Lua代码,其中函数和变量可用于同一目录中的Pongo2、Amber和Markdown页面。

如果将单个Lua脚本作为命令行参数提供,用于独立服务器。它可用于设置处理程序或为特定URL前缀提供文件和目录。

style.gcss是GCSS代码,支持对同目录下的Pongo2,Amber和Markdown页面的样式。

总之,Algernon支持对以下文件扩展名的处理​​:

Markdown:.md(渲染为HTML)

Pongo2:.po2,.pongo2或.tpl(渲染为任何文本,通常为HTML)

琥珀色:.amber(渲染为HTML)

Sass:.scss(渲染为CSS)

GCSS:.gcss(渲染为CSS)

JSX:.jsx(渲染为JavaScript / ECMAScript)

Lua:.lua(提供自己的输出和内容类型的脚本)

HyperApp:.hyper.js或.hyper.jsx(渲染为HTML)

根据扩展名为其他文件指定mimetype。

没有索引文件的目录显示为目录列表。

尽可能使用UTF-8。

可以通过命令行或lua脚本配置服务器,但是配置是非必须的,默认无需配置既可以使用。

技术特点

支持HTTP,HTTP/2,默认启动HTTPS(HTTP/2需要浏览器支持)。

支持Lua动态程序,可以使用Lua脚本处理程序。

Algernon可执行文件为本机静态编译编,速度相当快。

适用于Linux,OS X和64位Windows。

Lua解释器被编译为可执行文件。

支持热部署自动刷新功能,实时编辑/实时预览。

自包含的Algernon应用程序可以压缩到存档(以.zip或.alg结尾),支持子启动时加载。

内置支持Markdown,Pongo2,Amber,Sass(SCSS),GCSS和JSX。

默认情况下,使用Redis作为数据库后端,如果没有可用的Redis服务器,Algernon将使用内置的Bolt数据库。

可以对Markdown渲染的HTML页面指定以MultiMarkdown语法的标题:

title: Title内容。

后台无需要文件转换器(如SASS)即可进行文件转化。

如果设置了autorefresh,源文件时自动刷新页面。

交互式REPL。

如果Markdown文件名作为第一个参数,则它将在端口3000上提供预览,无需任何数据库。方便在本地查看README.md文件。

完全多线程。将使用所有可用的CPU。

支持通过tollbooth进行速率限制。

Lua REPL提供了帮助命令,可快速浏览可用的Lua功能。

可以加载用任何语言编写的插件。插件必须提供Lua.Code和Lua.Help函数,并通过stderr + stdin来交互JSON-RPC。

内置线程安全文件缓存,具有多种可用缓存模式(例如,仅用于缓存图像)。

可以读取并保存到JSON文档。支持简单的JSON路径表达式(如简单版本的XPath,但对于JSON)。

支持缓存压缩,可以将缓存中存储的文件直接从缓存发送到客户端,无需解压缩。

对大于4096B的文件发送到客户端的文件默认使用gzip压缩。

使用PostgreSQL作为后端数据库时候,默认使用HSTORE键/值类型(PostgreSQL 9.1或更高版本)。

没有外部依赖,纯Golang程序。

需要Go 1.12或更高版本。另外用于QUIC支持的包不支持使用gccgo(GCC)构建。

安装

OS X

苹果OS X系统可以使用包管理器直接安装:

brew install algernon

如果没有安装Homebrew包管理器,请先安装。

Arch Linux

可以使用AUR源安装:

pacman -S algernon

二进制包

其他系统请下载对应二进制包即可使用。

源码安装

从源码编译安装,适用于任何系统。用get命令从官方主分支下载最新源码

get -u github/xyproto/algernon

使用该方法安装,需要先设置GOPATH, 并将$GOPATH/bin添加到执行PATH中

export GOPATH =~/go

export PATH = $PATH:$GOPATH/bin

也可以先git clone到本地然后编译安装

Golang 1.12版本

早期Golang版本

docker容器

Algernon基本使用

运行Algernon:

以开发者模式运行

algernon -e

该命令启用调试模式,以内置的Bolt数据库,以HTTP形式启动,并对除了以下类型的其他文件启用缓存,这些类型包括Pongo2,Amber,Lua,Sass,GCSS,Markdown和JSX。

新建一个简单的hello lua文件index.lua:

浏览器访问,结果如下:

自定义Algernon应用程序

创建应用目录:

mkdir mypage && cd mypage

创建名为index.lua的文件,其中包含以下内容和上面一样。

启动:

algernon --httponly --autorefresh .

启动增加参数autorefresh,使得文件编辑后可以热加载实时生效。可以试着编辑下index.lua并刷新浏览器以查看新结果。

注意—autorefresh对Markdown,Pongo2和Amber页面也生效,比如我新建一个chongchong.md页面:

然后浏览器访问:

HTTP/2 和HTTPS支持应用

利用openssl创建创建自签名证书,仅用于测试:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3000 -nodes

结果中,按照提示中按Return键,在Common Name时候输入任意名称,我们输入的是CC,就会在本目录生成cert.pem和key.pem两个证书文件

启动

algernon .

然后通过浏览器以https访问:

:3000

由于使用子签名证书,没有添加根域证书,需要在浏览器添加信息才能访问。

注意https头信息,确实是HTTP/2。

Lua支持

基本的Lua功能

//返回服务器的版本字符串。

version() -> string

//睡眠给定的秒数(可以是浮点数)。

sleep(number)

//将给定的字符串记录为信息。采用可变数量的字符串。

log(...)

//将给定的字符串记录为警告。采用可变数量的字符串。

warn(...)

//将给定的字符串记录为错误。采用可变数量的字符串。

err(...)

//返回1970年的纳秒数(Unix时间)

unixnano() -> number

//将Markdown转换为HTML

markdown(string) -> string

//返回运行REPL或脚本的目录。如果给出了文件名(可选),则返回脚本运行的路径,使用路径分隔符和给定的文件名连接。

scriptdir([string]) -> string

//返回运行服务器的目录。如果给出了文件名(可选),则返回服务器运行的路径,使用路径分隔符和给定的文件名连接。

serverdir([string]) -> string

Lua插件

//在给定可执行文件路径的情况下加载插件。成功时返回true。如果在Lua提示符上调用,将返回插件帮助文本。

Plugin(string)

//给定一个插件路径,返回插件中Lua.Code函数返回的Lua代码。可能会返回一个空字符串。

PluginCode(string) -> string

//获取插件路径,函数名称和参数。如果函数调用失败,则返回空字符串;如果成功,则返回结果为JSON字符串。

CallPlugin(string, string, ...) -> string

Lua代码库函数

这些函数可以与插件函数结合使用,用于存储加载serverconf.lua时插件返回的Lua代码,然后在处理请求时检索Lua代码。

//创建或使用代码库对象。 (可选)将数据结构名称作为第一个参数。

CodeLib([string]) -> userdata

//给定命名空间和Lua代码,将给定代码添加到命名空间。成功时返回true。

codelib:add(string, string) -> bool

//给定命名空间和Lua代码,将给定代码设置为命名空间中的唯一代码。成功时返回true。

codelib:set(string, string) -> bool

//给定命名空间,返回Lua代码或空字符串。

codelib:get(string) -> string

//将给定命名空间中的(eval)代码导入当前的Lua状态。成功时返回true。

codelib:import(string) -> bool

//完全清除代码库。成功时返回true。

codelib:clear() -> bool

Lua文件上传函数

//创建文件上传对象。采用表单ID(来自POST请求)作为第一个参数。将可选的最大上载大小(以MiB为单位)作为第二个参数。

//失败时返回nil和错误字符串,成功时返回userdata和空字符串。

UploadedFile(string[, number]) -> userdata, string

//返回客户端指定的上传文件名

uploadedfile:filename() -> string

//返回已接收数据的大小

uploadedfile:size() -> number

Lua处理请求函数

//设置页面的Content-Type。

content(string)

//返回请求的HTTP方法(GET,POST等)。

method() -> string

//将文本输出到浏览器/客户端。采用可变数量的字符串。

print(...)

//返回请求的URL路径。

urlpath() -> string

//返回请求中的HTTP标头,给定键或空字符串。

header(string) -> string

//在给定键和值的情况下设置HTTP标头。

setheader(string, string)

更多函数支持请参考官方文档,此处略。

Markdown支持

Algernon实现对Markdown的快速浏览,实现在线webMarkdown查看器。-m标志用来启动:

algernon -m README.md在浏览器中查看README.md。

除了常规的Markdown语法之外,Algernon还支持在Markdown文件的顶部设置页眉标题和语法高亮样式,如下所示:

该代码将使用highlight.js突出显示代码,并提供多种样式。

replace_with_theme后面的字符串将用于替换当前主题字符串与给定字符串。这使得可以为一个主题使用一个图像(如logo_default_theme.png)。主题可以是light,dark,redbox,bw,github,wing,material,neon,default,werc或CSS文件的路径。或者同一目录下的style.gcss文件自定义的样式。

范例和截图

官方提供了大量的范例可以供使用,可以在官方仓下载samplepack.zip安装包,解压到web目录更目录然后通过浏览器就可以访问。

bootstrap小应用

hyperapp计数

这是在启用调试模式时处理Lua脚本中的错误的方法。

three.js

Algernon Charles Swinburne的一首诗,背景中有三个旋转的圆环。使用CSS3高斯模糊,使用three.js作为3D图形。

prettify代码美化

美化样本的屏幕截图,由单个Lua脚本提供。

todo小程序

使用Alact和Algernon交互使用

tiles图片拼图小游戏