分类
OpenResty

我的第一段 OpenResty 代码

前端同学需要一个上传文件的后端做一些调试,我刚好有,就给她用了。然后遇到跨域问题,一般来说我会在 PHP 里解决,不过这次我想挑战一下 nginx,于是找到这个答案。照做之后,OPTIONS 请求按照预期返回了正确的头,但是 POST 不行。

于是我在群里请教同事,结果被老板批评:

  1. 在 nginx 里,“IF is evil”,因为要在一些特定条件下,它的行为会跟预期完全相反;有时候甚至会引起 segfault
  2. 我厂是 OpenResty,没理由不用 OpenResty

行吧,本来就是为了跨出舒适区,不妨走远一点,OpenResty 就 OpenResty。

0. 用 OpenResty 替换 Nginx

我的系统是 Ubuntu 18.04,所以先按照 官方文档 安装最新版本的 OpenResty。

安装完成之后,可以通过 service --status-all 查看服务列表,不出意外的话,能看到 openresty 服务。

停掉 nginx,然后启动 openresty:

service nginx stop
service openresty start

此时 openresty 的配置位于 /usr/local/openresty/nginx/conf/nginx.conf,默认的 web 服务地址是 /usr/local/openresty/nginx/html/,所以我们需要修改一下,以便继续使用 /var/www/html,也就是之前 nginx 的网页文件。

1. 继续使用 nginx 的配置

修改配置的方式很简单,OpenResty 本来也兼容 nginx 的配置。对于我而言,最简单的做法是干掉 server 的部分,然后加载 nginx 的网站配置,也就是这两句:

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

此处会有个小问题:PHP 网站的配置里需要加载 snippets/astcgi-php.conf,默认使用的是相对路径,需要改成绝对路径 /etc/nginx/snippets/fastcgi-php.conf

至于其它配置,比如 gzipssl 等,酌情拷过来即可。

2. 增加配置以自动输出请求头

最后就是写 lua,这部分难度不大,基本就是普通的 lua 和 nginx lua API。写好的配置是这样的:

location / {
  access_by_lua_block {
    if ngx.req.get_method() == 'POST' then
      ngx.header['Access-Control-Allow-Origin'] = '*';
      ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS';
      ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      ngx.header['Access-Control-Allow-Expose-Headers'] = 'Content-Length,Content-Range';
 
    elseif ngx.req.get_method() == 'OPTIONS' then
      ngx.header['Access-Control-Allow-Origin'] = '*';
      ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS';
      ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      ngx.header['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS';
      ngx.header['Access-Control-Allow-Headers'] = 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      ngx.header['Access-Control-Max-Age'] = 1728000;
      ngx.header['Content-Type'] = 'text/plain; charset=utf-8';
      return 204;
    end
  }
  # First attempt to serve request as file, then
  # as directory, then fall back to displaying a 404.
  try_files $uri $uri/ /index.php$args;
}

首先,使用 access_by_lua_block 添加 lua 代码块。这里注意,一定要用 access_by_lua_block,不能用 content_by_lua_block,因为我们后面还要用 proxy_pass 把请求反向代理给 php-fpm 处理,而 content_by_lua_block 就直接返回了。

然后,因为要添加 headers,所以要在能输出其它内容前先输出头。所以这个代码块要放在最前面,前面不能有其它输出。

3. 总结

需求不大,代码也比较简单,不过还是花了大约一天的时间调试。将来可能会写更多的 OpenResty lua,到时候再慢慢分享咯。

另外我也搞不清楚为啥 nginx 这么流行的一个软件竟然有 if 这种问题。有知道的同学请指教。