前篇 使用 Docker 和 Node 搭建公式渲染服务( 二 )


version: "3.0"services:nginx:image: nginx:1.19.8-alpinerestart: alwaysports:- 3000:80volumes:- ./default.conf:/etc/nginx/conf.d/default.confnetworks:- formulahealthcheck:test: ["CMD-SHELL", "wget -q --spider --proxy off localhost/get-health || exit 1"]interval: 10stimeout: 1sretries: 3logging:driver: "json-file"options:max-size: "1m"math-api:restart: alwaysimage: chialab/math-apiexpose:- 3000networks:- formulalogging:driver: "json-file"options:max-size: "1m"networks:formula:这里我们主要做了两件事:

  1. 将两个应用放置相同的容器网络中 。
  2. 由 Nginx 接受公开的网络请求,然后再转发给开源公式应用 。
如果你想了解如何使用 Nginx 提供 HTTPS 服务,并尽可能减少代码,可以翻阅前一篇文章;如果你想了解如何搭配 Traefik 一起提供服务,也可以翻阅之前有关 Traefik 的内容,这里不做赘述 。
接着我们编写 Nginx 基础配置:
server {listen 80;# 限制只渲染最大1K数据,避免服务被恶意攻击client_max_body_size 1k;access_log off;location / {proxy_pass http://math-api:3000;}location = /get-health {access_log off;default_type text/html;return 200 'alive';}}将配置保存为 default.conf,然后使用 docker-compose up 启动服务 。
依旧访问前文中的本地端口,这次我们可以将公式内容替换为前文中知乎公式图片的内容:
http://localhost:3000/render?input=latex&inline=0&output=svg&width=256&source=%5Cbegin%7Balign%7D%26%5Cprod_%7Bn%3D1%7D%5E%5Cinfty%5Cfrac%7B%28n%2Ba_1%29%28n%2Ba_2%29...%28n%2Ba_k%29%7D%7B%28n%2Bb_1%29%28n%2Bb_2%29...%28n%2Bb_k%29%7D%5C%5C%26%3D%5Cfrac%7B%5CGamma%281%2Bb_1%29%5CGamma%281%2Bb_2%29...%5CGamma%281%2Bb_k%29%7D%7B%5CGamma%281%2Ba_1%29%5CGamma%281%2Ba_2%29...%5CGamma%281%2Ba_k%29%7D%5Cend%7Balign%7D
前篇 使用 Docker 和 Node 搭建公式渲染服务

文章插图
 
针对复杂公式的渲染
可以看到图片渲染的“非常漂亮” 。
使用 Nginx 减少请求参数减少参数可以使用非常多的方式,这里选择一种最基础的方案,来自 ngx_http_core_module 的 set args 来强制声明请求参数:
server {listen 80;# 限制只渲染最大1K数据,避免服务被恶意攻击client_max_body_size 1k;access_log off;location / {set $args $args&input=latex&inline=0&output=svg&width=256;proxy_pass http://math-api:3000;}location = /get-health {access_log off;default_type text/html;return 200 'alive';}}重新启动服务,你会发现上面的请求参数可以被简化为下面这样:
http://localhost:3000/render?source=%5Cbegin%7Balign%7D%26%5Cprod_%7Bn%3D1%7D%5E%5Cinfty%5Cfrac%7B%28n%2Ba_1%29%28n%2Ba_2%29...%28n%2Ba_k%29%7D%7B%28n%2Bb_1%29%28n%2Bb_2%29...%28n%2Bb_k%29%7D%5C%5C%26%3D%5Cfrac%7B%5CGamma%281%2Bb_1%29%5CGamma%281%2Bb_2%29...%5CGamma%281%2Bb_k%29%7D%7B%5CGamma%281%2Ba_1%29%5CGamma%281%2Ba_2%29...%5CGamma%281%2Ba_k%29%7D%5Cend%7Balign%7D那么是不是优化就到此为止了呢,显然不是的,如果我们构造有风险的参数、亦或者接收到了被我们固化的参数,参数类型产生变化,那么服务还是存在一定的隐患 。
比如,我们在定义了 output 参数后,依旧传递了这个参数:
http://localhost:3000/render?output=png&...则会收到诸如 {"message":"Invalid output: png,svg"} 的错误提示 。
为了避免这类错误,所以我们可以进一步改造上面的配置:
server {listen 80;# 限制只渲染最大1K数据,避免服务被恶意攻击client_max_body_size 1k;access_log off;location / {if ( $arg_source = '') {return 404;}set $args source=$arg_source&input=latex&inline=0&output=svg&width=256;proxy_pass http://math-api:3000;}location = /get-health {access_log off;default_type text/html;return 200 'alive';}}重启服务,你会发现即使再构造类似下面请求,服务也不会发生错误了 。
http://localhost:3000/render?output=png&source=%5Cbegin%7Balign%7D%26%5Cprod_%7Bn%3D1%7D%5E%5Cinfty%5Cfrac%7B%28n%2Ba_1%29%28n%2Ba_2%29...%28n%2Ba_k%29%7D%7B%28n%2Bb_1%29%28n%2Bb_2%29...%28n%2Bb_k%29%7D%5C%5C%26%3D%5Cfrac%7B%5CGamma%281%2Bb_1%29%5CGamma%281%2Bb_2%29...%5CGamma%281%2Bb_k%29%7D%7B%5CGamma%281%2Ba_1%29%5CGamma%281%2Ba_2%29...%5CGamma%281%2Ba_k%29%7D%5Cend%7Balign%7D以及,是如果未传递公式内容请求服务,也会由 Nginx 直接返回一个 404 Not Found,而不是直接将错误请求透传到公式应用 。
最后迄今为止,我们已经使用 Nginx 和开源软件 Math-API 搭建了一个基础的公式服务 。


推荐阅读