部署 记一次部署时出现 CSS FingerPrint 不一致的问题

jicheng1014 · March 26, 2019 · Last by Repairtech replied at July 25, 2019 · 8143 hits
Topic has been selected as the excellent topic by the admin.

以前一直是前后端分离,最近实在是受不了 react 和 rails api 切来切去的人格分裂,于是退回到 rails 渲染 前端

说实在的,在页面不复杂的情况下 ( 小型内部用邮件,短信,身份核验管理 ),套一个 bootstrap sb2 admin 的模板,turbolinks + SRJ, 比折腾 antd 强很多

很快开发就结束了,就只剩下部署。

我的部署机器是这样规划的:有两台机器 club_001 和 club_002 001 有公网 IP, 002 没有,同时 002 的性能剩余稍多

我的这个小项目就打算部署到 002 上,之后由于 002 上是没有装 nginx 的,直接由 001 upstream 过来

这里遇到了第一个麻烦之处:

由于 nginx 是装在 001 上的,而项目在 002 上,所以 002 生成的静态文件,是没有办法直接被 nginx 访问到的

(下面常规的 nginx 配置是有问题的,因为 nginx 无法访问到 002 的 /var/www/tube_center/current/public)

server {
listen 80;
  listen 443 ssl;

  ssl_certificate /root/.acme.sh/cer;
  ssl_certificate_key /root/.acme.sh/key;
  server_name tubecenter.xxxxx.com;
  root /var/www/tube_center/current/public;
  try_files $uri/index.html $uri @puma_tubecenter_production;


  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  location @puma_tubecenter_production {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_redirect off;
    proxy_pass http://puma_tubecenter_production;
  }

  if ($request_method !~ ^(GET|HEAD|PUT|PATCH|POST|DELETE|OPTIONS)$ ){
    return 405;
  }
}

怎么解决?最简单的 就是在 cap 的 assets:compile after 加上脚本进行拷贝,只不过因为要改 deploy , 遂放弃

我选择了另一种方案,就是在 001 也部署这个项目,但是这个项目仅仅只做 precompile 就好了,以后万一需要也负载到 001 号机器,也修改最少

于是,修改 deploy.rb 文件

server "club-api001",  roles: %w{web}
server "club-api002",  roles: %w{web app db}

默认 web 会生成 assets, puma 会运行在 app 上

之后执行 cap production deploy

一切正常,但是访问的时候,出现了问题

css 加载不出来,

我看源码,编译正常 css 和 js 都有 fingerprint, 而且 js 的竟然还能访问,

于是我登录两台机器查看究竟,

发现两台机器编译出来的 css fingerprint, 竟然不一致

同时,我又发现另外一个我自己写的 devise.css 的是一致的,

所以推论得出 scss 应该工作的是正常的,

那么问题就出在了 application.css

cat 这两个文件,格式化 放到 text differ 进行对比,发现了一个有意思的地方

看起来似乎是循环下的随机数,于是以 css class name 为搜索条件,去搜索 发现了一个 sb2 admin template 留给我的惊喜

// _error.scss

@keyframes noise-anim {
  $steps: 20;
  @for $i from 0 through $steps {
    #{percentage($i*(1/$steps))} {
      clip: rect(random(100)+px,9999px,random(100)+px,0);
    }
  }
}

这里看到 有一个叫做 random 的函数

在此最终找到原因

scss 在编译的时候,由于使用了随机数,导致了每次编译的 css 文件都 不一样, 所以 css 的最终内容不一致 所以 在 002 号的 puma 就找不到 001 里和自己生成的 assets 一样的文件

解决的办法也很简单,就把 random 函数去掉,用固定值即可

最后在重新编译的时候并未发现 assets 里的文件变化,于是修改 initializers/assets.rb 文件里的

Rails.application.config.assets.version = '2.1'  # 新编号

即可重新编译 assets

至此,css 的 fingerprint 不一致的问题 就这样解决了。

其实实际中解决的比较着急,因为太久没有做 rails 的前端了,很多地方都在瞎猜,搞了很多 对比环境的工作,打 docker 什么的,方向走的不对

最后总结下:

  1. 相信科学,不要瞎猜。分析问题,先易后难,先大概率,再小概率
  2. 在引入别人的内容时,需要小心谨慎
  3. 如无必要,不要在 sass 里用 random

虽然我不用 cap,但是 cap 好像有 mirror

有意思。

Reply to pynix

在官网上没找到相关内容呢 这个我还真不是太了解

追根溯源地解决问题是最有成就感的事情。

取巧就是修改 public/assets/.sprockets-manifest 这个隐藏文件

hooopo mark as excellent topic. 28 Mar 12:29
Reply to stargwq

感谢刘老板赐教

@tanhui2333 不过其他的比较 ok

You need to Sign in before reply, if you don't have an account, please Sign up first.