Thảm cảnh deploy nhiều source trên cùng server (Phần 3)

Đăng bởi Lưu Đại vào ngày 19-01-2024
Sau khi dùng thử một thời gian thì mình lại thấy hai vấn đề: 
  • Vấn đề 1: Mỗi khi reload lại trang mà path là /bo/{một cái gì đó} thì trang sẽ trả về 404. 
  • Vấn đề 2: Mỗi khi deploy code mới thì client không tự động lấy các file js, css mới về mà vẫn sử dụng các file cũ. 

Để giải quyết vấn đề 2 thì mình cần phải force reload trang của người dùng mỗi khi deploy => Phải giải quyết vấn đề 1 trước đã. 
Sau đây là cách mình đã dùng. Không biết có phải cách tốt nhất không nhưng hiện tại nó chạy được, sau này nếu có tìm được cách tốt hơn thì sẽ viết thêm bài mới. 

1. Mỗi khi reload lại trang mà path là /bo/{một cái gì đó} thì trang sẽ trả về 404

- Nguyên nhân: Lỗi này là do app vuejs của mình là SPA chứ không phải SSR. Đối với SSR mỗi khi người dùng truy cập 1 trang thì client sẽ gửi request lên server để lấy html đã được server render về. Đối với SPA nó sẽ chỉ load html, css, js lúc mới ban đầu vào trang, còn khi sang trang mới thực chất là chỉ có phần url bị thay đổi chứ không có gửi thêm request nào lên server cả (server ở đây là server fe nhé tránh nhầm vs server be khi gọi api). Vậy nên khi request /bo/abc lên server sẽ không hiểu và nhả lỗi 404.
- Cách fix: Cách mà vuejs recommend trên trang docs của nó là mỗi khi gặp request dạng này thì trả về cho nó index.html (config trên nginx hoặc reserve proxy khác)

location / {
  try_files $uri $uri/ /index.html;
}
Tuy nhiên nếu làm cách này trên server của mình thì sau khi request index.html nó sẽ lại soát lại tất cả location và nhảy vào location mặc định cuối cùng là app Rails. 
Sau một hồi thử rất nhiều cách thì mình làm như sau mình sẽ tách các location ra thành 
= /bo: Path phải đúng kiểu /bo thì mới vào
^~ /bo/assets: Dùng để serve file js css do hiện tại /bo/assets/xyz không còn được vào trực tiếp app fe nữa
^~ /bo/(.*\.(jpg|jpeg|png|gif)$): Tương tự như trên nhưng để serve file ảnh
~ /bo/*: Mỗi khi gặp request như này thì sẽ điều hướng về /bo => bo/abc sẽ về bo, bo/xyz cũng về bo
  location = /bo {
    proxy_pass http://app_fe_service/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Ssl on;
    proxy_set_header X-Forwarded-Port 443;
    proxy_set_header X-Forwarded-Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_redirect off;
    client_max_body_size 23M;
  }

  location ^~ /bo/assets {
    rewrite /bo/assets/(.*)$ /assets/$1 break;
    proxy_pass http://app_fe_service;
  }

  location ~* /bo/(.*\.(jpg|jpeg|png|gif)$) {
    rewrite /bo/(.*)$ /$1 break;
    proxy_pass http://app_fe_service;
  }

  location ~ /bo/* {
    rewrite /bo/* /bo last;
  }
Done giờ đã có thể thoải mái reload trang 😁. 

2. Mỗi khi deploy code mới thì client không tự động lấy các file js, css mới về mà vẫn sử dụng các file cũ

Nếu ai từng code Rails MVC thì sẽ biết mỗi khi build file js, css mới thì Rails sẽ hash nội dung và gán kết quả vào response header trước khi trả về cho client. Sau đó client sẽ lấy cái header này để so sánh với header file hiện tại nó đang giữ nếu bị lệch thì sẽ xóa cache và fetch lại file (lâu lâu rồi không biết nhớ đúng không nữa :D)
image.png

Ở đây mình sẽ làm giống vậy tuy nhiên thay vì xịn xò là mỗi khi build lại thì phải viết version vào 1 file rồi bên server lấy file đó ra thì mình tạm làm thủ công tức là khi nào muốn force update cho người dùng thì mình sẽ update version bằng tay. 
Trước tiên là server sẽ thêm 1 middlewares để viết header 
Thêm header này vào ExposeHeader trong middlewares cors phải làm vậy thì client mới được quyền dùng header này
image.png

Phía client mình dùng axios interceptor để xử lý
Hơi rối xíu vì mình dùng cái interceptor này cho vài cái xử lý khác nữa. 
Doneee