Khi bạn truy cập website, bạn mong muốn sẽ nhìn thấy nội dung xuất hiện càng nhanh càng tốt. Bạn cũng muốn rằng website này có thể được tìm kiếm dễ dàng trên Google. Đây chính là lúc kỹ thuật Server-Side Rendering (SSR) trở nên hữu ích.
Trước khi SSR phổ biến, nhiều website sử dụng Client-Side Rendering (CSR): nghĩa là khi người dùng truy cập, browser sẽ nhận được file HTML trống, sau đó load xuống file JavaScript rất lớn, rồi chạy JavaScript đó để tạo ra giao diện. Vấn đề ở đây là: phải chờ JavaScript load và chạy xong, người dùng mới thấy được nội dung. Điều này có thể khiến trang load chậm. Công cụ tìm kiếm cũng gặp khó khăn vì lúc crawler (bot của công cụ tìm kiếm) đến, nó thấy HTML gần như trống, có thể bị hiểu nhầm là nội dung sơ sài.
SSR ra đời để khắc phục: thay vì để browser tự build giao diện, sẽ dựng sẵn HTML ngay trên server và gửi nó về. Như vậy, khi người dùng truy cập, họ thấy nội dung ngay (vì HTML đã có sẵn). Sau đó, browser mới tải JavaScript để thêm tính tương tác. Cách làm này cải thiện trải nghiệm người dùng, hỗ trợ SEO tốt hơn, và vẫn giữ được sự linh hoạt khi cần nội dung động.
1. Server-Side Rendering là gì?
SSR (Server-Side Rendering) là quá trình tạo ra HTML của website trên máy chủ (server) thay vì để trình duyệt (client) làm việc ấy.
Ví dụ: nếu không có SSR, khi bạn vào website, bạn có thể nhận file HTML gần như rỗng: chỉ có <div id="root"></div>
. Browser phải chạy JavaScript để tạo giao diện. Nếu như với SSR, khi bạn vào website, bạn nhận ngay đoạn HTML đã chứa đầy đủ <h1>Tiêu đề</h1><p>Nội dung trang...</p>
. Browser hiển thị ngay nội dung mà bạn không phải chờ đợi.
2. Tại sao SSR quan trọng?
2.1 Người dùng thấy nội dung sớm hơn
Khi trang web của bạn được render từ phía server (SSR), server sẽ xử lý ứng dụng và trả về đoạn HTML hoàn chỉnh ngay khi có yêu cầu. Khác với Client-Side Rendering (CSR), browser của bạn ban đầu nhận được một file HTML gần như trống (chỉ chứa vài thẻ cơ bản và một div trống), sau đó phải tải file JavaScript, phân tích và thực thi JavaScript để dựng giao diện hoàn thiện. Quá trình này ở CSR có thể mất thời gian, đặc biệt đối với kết nối internet chậm hoặc thiết bị yếu.
Với SSR, ngay khi người dùng truy cập trang, bạn nhận được một khối HTML đã đầy đủ nội dung. Browser chỉ cần parse và hiển thị nó ngay lập tức, thay vì phải chờ đợi JavaScript load xong và hoàn thiện giao diện. Kết quả là người dùng sẽ thấy nội dung hiển thị trên màn hình nhanh chóng hơn rất nhiều. Thời gian hiển thị thông tin ban đầu (First Contentful Paint - FCP) được rút ngắn, tạo cảm giác "nhanh" hơn, giảm khả năng người dùng rời khỏi trang do chờ đợi lâu.
2.2 Tốt cho SEO (Tối ưu hóa công cụ tìm kiếm)
Trong mô hình CSR, khi bot tìm kiếm truy cập vào website, ban đầu nó có thể thấy HTML rất ít nội dung, phải chờ để "chạy" JavaScript mới thấy nội dung thật sự. Việc này có thể làm công cụ tìm kiếm gặp khó khăn hoặc chậm trễ trong việc lập chỉ mục nội dung, hoặc tệ hơn, một số công cụ tìm kiếm yếu hơn không thấy được nội dung đầy đủ nếu không xử lý được JavaScript - giảm performance rất nhiều.
Ngược lại, với SSR, khi bot của công cụ tìm kiếm vào trang, HTML đã sẵn sàng với đầy đủ nội dung. Bot không cần phải chờ JavaScript chạy để có giao diện hoàn chính; nội dung đã hiển thị ngay trong HTML ban đầu. Điều này giúp công cụ tìm kiếm dễ dàng đọc, hiểu, và lập chỉ mục nội dung của trang. Kết quả là trang của bạn có cơ hội xếp hạng cao hơn trong kết quả tìm kiếm, thu hút nhiều lượt truy cập hơn.
2.3 Phù hợp cho nội dung tùy biến theo người dùng
Nhiều website ngày nay cần hiển thị nội dung khác nhau cho từng người dùng dựa trên thông tin đăng nhập, cookies, session, hoặc token gửi kèm request. Ví dụ:
- Website thương mại điện tử muốn hiển thị giá khuyến mãi riêng cho khách hàng VIP.
- Social Website hiển thị nguồn tin (feed) cá nhân dựa trên bạn bè của người dùng.
- Dashboard doanh nghiệp chỉ hiển thị dữ liệu dựa trên quyền của tài khoản đã đăng nhập.
Với SSR, bạn có thể thực hiện logic xác thực và xử lý dữ liệu người dùng ngay trên server. Server sẽ dựa vào cookie, token, hoặc thông tin phiên đăng nhập, sau đó render giao diện đã được "cá nhân hóa" trước khi gửi về browser. Nhờ vậy, người dùng khi truy cập sẽ thấy ngay nội dung phù hợp với họ mà không cần phải đợi tự browser fetch dữ liệu và cập nhật lại giao diện.
3. Cơ chế hoạt động của SSR
Hãy tưởng tượng bạn có website được viết bằng React. Thông thường nó sẽ hoạt động như thế này:
- Browser yêu cầu trang.
- Server trả về HTML rỗng + file JavaScript lớn.
- Browser load và chạy JavaScript, cuối cùng mới thấy nội dung.
Đối với cơ chế hoạt động của SSR bạn hãy xem qua hình phía dưới, kết hợp phần giải thích của mình bên dưới để hiểu rõ hơn nhé.
- Người dùng thực hiện hành động, ví dụ như nhập URL vào thanh địa chỉ trên browser hoặc click vào một liên kết dẫn đến website. Browser lúc này sẽ gửi request HTTP (GET request) đến server để yêu cầu nội dung của trang.
- Khi hành động request được thực hiện, browser sẽ gửi request HTTP tới server của ứng dụng. Request này chứa: URL của trang, các thông tin liên quan khác như: cookies, headers để server có thể xử lý.
- Server nhận request từ browser và bắt đầu thực hiện các công việc sau:
- Truy xuất dữ liệu từ databases.
- Kết nối đến các API.
- Lấy các file tĩnh cần thiết như là: hình ảnh, CSS,...
- Server gửi các yêu cầu API để lấy dữ liệu: quá trình này, server sẽ gửi API calls đến backend hoặc bên thứ ba để lấy dữ liệu.
Ví dụ: nếu người dùng truy cập trang sản phẩm, server có thể gửi request đến một API để lấy thông tin chi tiết của sản phẩm (tên, giá, hình ảnh, mô tả,...).
Ngoài ra, server có thể tải các file CSS hoặc hình ảnh cần thiết để đưa vào giao diện HTML. - Server render website
- Sau khi có tất cả dữ liệu (Database, API,...), server sẽ sử dụng framework hoặc công cụ JavaScript.
- Server sẽ:
- Render các thành phần giao diện thành code HTML tĩnh.
- Chèn dữ liệu động vào các phần thích hợp của HTML.
- Kết quả là trang HTML đã hoàn chỉnh, chứa đầy đủ thông tin và cấu trúc giao diện.
- Server gửi HTML, CSS và JavaScript tới browser
- HTML hoàn chỉnh (đã render), CSS (định dạng giao diện), và các file JavaScript (logic động) sẽ được gửi từ server về browser của người dùng.
- Khi browser nhận được các file này:
- HTML: được parse và hiển thị ngay lập tức. Người dùng có thể thấy nội dung tĩnh gần như ngay lập tức mà không cần chờ load JavaScript.
- CSS: được tải để áp dụng định dạng cho HTML, giúp giao diện trang trở nên đẹp và đầy đủ.
- JavaScript: được tải xuống nhưng chưa chạy.
Lúc này là người dùng đã có thể nhìn thấy nội dung tĩnh của trang.
- Browser chạy JavaScript (hydrate)
Khi JavaScript được tải xong, browser sẽ:
- Chạy các logic động được định nghĩa trong ứng dụng (thông qua JavaScript).
- Gắn các event handlers (trình xử lý sự kiện, ví dụ: click, hover) vào các thành phần HTML.
Quá trình này được gọi là Hydration, trong đó JavaScript "kích hoạt" các thành phần giao diện đã render trên server, biến chúng từ HTML tĩnh thành các thành phần tương tác động.
- Website hiển thị và tương tác được
Sau khi hoàn tất các bước trên, trang web trở nên đầy đủ và tương tác được. Người dùng có thể:
- Xem nội dung mà không cần chờ lâu vì HTML được render sẵn.
- Tương tác với trang như: onClick vào button, submit form,...
4. SSR cải thiện hiệu suất
Trên là hình ảnh tóm tắt cách SSR hoạt động và các chỉ số quan trọng liên quan đến hiệu suất:
- TTFB (Time to First Byte): thời gian từ khi browser gửi request đến khi nhận được byte đầu tiên từ server.
- FCP (First Contentful Paint): thời gian để nội dung đầu tiên xuất hiện trên màn hình.
- LCP (Largest Contentful Paint): thời gian để phần nội dung lớn nhất (tiêu đề hoặc hình ảnh chính) hiển thị hoàn chỉnh.
- TTI (Time to Interactive): thời gian để website có thể tương tác.
5. Hạn chế của SSR?
5.1 Chi phí server tăng cao
- Nguyên nhân:
- Với mỗi request từ người dùng, server phải thực hiện công việc: xử lý request, Fetch dữ liệu từ API hoặc cơ sở dữ liệu, render giao diện thành HTML.
- Nếu có nhiều người dùng truy cập đồng thời, tải trọng trên server tăng lên rất nhanh.
- Hậu quả:
- Server cần tài nguyên mạnh hơn (CPU, RAM) để xử lý nhiều request trong cùng lúc.
- Chi phí vận hành server (hosting) có thể tăng cao, đặc biệt với các website có lưu lượng truy cập lớn.
- Một số giải pháp:
- Caching HTML đã render để tái sử dụng, giảm tải cho server.
- Streaming SSR: gửi HTML từng phần để giảm thời gian xử lý.
Ví dụ như trang tin tức với hàng triệu lượt truy cập mỗi ngày. Nếu sử dụng SSR mà không caching, server phải render hàng triệu lần/ngày, chi phí phát sinh sẽ rất lớn.
5.2 Phức tạp hơn trong triển khai và bảo trì
- Nguyên nhân:
- SSR đòi hỏi bạn phải chạy JavaScript trên server (thường là môi trường Node.js).
- Cần đồng bộ logic giữa server (SSR) và client (hydrate). Ví dụ:
- Dữ liệu nào nên render trên server, dữ liệu nào nên fetch trên client?
- Làm sao để tránh render lặp lại nội dung đã có?
- Khó khăn trong việc bảo trì:
- Codebase phức tạp hơn vì cần xử lý cả logic server và client.
- Phải quản lý hiệu năng server, caching, và đồng thời tối ưu SEO.
Ví dụ như bạn có một ứng dụng React bình thường có thể chạy trên client chỉ với một file HTML. Nhưng khi thêm SSR, bạn cần:
- Thiết lập server Node.js.
- Kết hợp thêm framework như Next.js hoặc tự xây dựng SSR.
- Quản lý quá trình hydrate sau khi server render xong.
5.3 TTFB (Time To First Byte) tăng so với SSG
TTFB là thời gian từ khi người dùng gửi request đến khi họ nhận được byte đầu tiên của phản hồi từ server. Với SSR:
- Server phải render HTML mỗi khi có request.
- Điều này làm TTFB cao hơn so với Static Site Generation (SSG), nơi server chỉ cần trả về một file HTML tĩnh đã được tạo sẵn.
Trang có thể mất thêm vài mili giây đến vài giây trước khi người dùng nhận được byte đầu tiên. Nếu server chậm hoặc phải xử lý quá nhiều request, thời gian phản hồi có thể kéo dài, làm giảm trải nghiệm người dùng.
Cá nhân mình gặp trường hợp này, thường sẽ sử dụng caching để lưu trữ HTML render sẵn và sử dụng Edge Rendering (SSR tại các máy chủ CDN) để giảm độ trễ.
Ví dụ: trang e-commerce dùng SSG có thể trả về HTML tĩnh trong 50ms. Nhưng với SSR, nếu server phải fetch dữ liệu từ API, render HTML, rồi mới trả về, TTFB có thể lên đến 200ms.
6. Khi nào nên sử dụng SSR?
Server-Side Rendering (SSR) không phải lúc nào cũng là lựa chọn tốt nhất, vì nó đi kèm với chi phí và sự phức tạp cao hơn. Theo cá nhân mình thấy thì những trường hợp cụ thể khi SSR thực sự mang lại lợi ích lớn và phù hợp với nhu cầu của bạn:
- Bạn mong muốn website của bạn xếp hạng cao trên các công cụ tìm kiếm như Google. Nội dung của bạn phải được hiển thị đầy đủ ngay trong HTML, để các bot của công cụ tìm kiếm có thể lập chỉ mục (indexing) chính xác.
- Vậy thì tại sao lại phù hợp?
- Crawler không cần chạy JavaScript để "hiểu" nội dung, vì tất cả đã có sẵn trong HTML.
- Các trang CSR có thể bị crawler bỏ qua nếu JavaScript bị lỗi hoặc browser của bot không hỗ trợ.
- Web của bạn không thể sử dụng các file HTML tĩnh vì nội dung thay đổi liên tục hoặc phụ thuộc vào người dùng cụ thể như: dashboard, profile,...
- SSR cho phép server xử lý logic tùy chỉnh trước khi gửi HTML cho client.
- Người dùng nhận được trang cá nhân hóa ngay từ đầu, không phải chờ client fetch dữ liệu và cập nhật giao diện.
- Bạn cần website hiển thị nội dung nhanh nhất có thể để giữ chân người dùng, thời gian hiển thị nội dung đầu tiên (FCP) đóng vai trò quan trọng trong việc giảm tỷ lệ thoát (bounce rate) như landing page marketing, homepage.
- HTML được render sẵn và gửi về ngay, giúp browser hiển thị nội dung gần như ngay lập tức.
- Cải thiện trải nghiệm người dùng, đặc biệt với những người dùng có kết nối mạng chậm hoặc thiết bị yếu.
Nếu trang của bạn là SPA nội bộ, không cần SEO, SSR có thể không cần thiết. Nếu trang ít thay đổi, SSG (tạo tĩnh) có thể nhanh hơn. SSR phù hợp khi bạn cần linh hoạt và thân thiện SEO, nhưng chấp nhận phức tạp hơn.
7. SSR với framework NextJS
Việc tự code SSR sẽ giúp bạn hiểu rõ cơ chế, nhưng thường khá vất vả. Framework Next.js sẽ lo phần nặng nhọc. Với Next.js bạn không phải tự cấu hình SSR, mọi thứ đều tự động. Bạn chỉ cần tập trung vào logic ứng dụng.
export async function getServerSideProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const post = await res.json();
return { props: { post } };
}
export default function Home({ post }) {
return (
<main>
<h1>SSR with Next.js</h1>
<h2>{post.title}</h2>
<p>{post.body}</p>
</main>
);
}
Truy cập http://localhost:3000
, bạn thấy nội dung ngay vì Next.js đã SSR sẵn, không cần bạn viết renderToString
như bên React.
Không phải là SSR lúc nào cũng nhanh, đây là một vài cách mình hay sử dụng
- Caching: Lưu kết quả SSR vào bộ nhớ hoặc CDN. Nếu dữ liệu ít thay đổi, thay vì render mỗi request, bạn cache vài chục giây.
let cachedData = null;
let lastFetch = 0;
server.get('*', async (req, res) => {
const now = Date.now();
if (!cachedData || (now - lastFetch) > 10000) {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/4');
cachedData = await response.json();
lastFetch = now;
}
});
- Streaming SSR (React 18): Thay vì chờ render xong toàn bộ trang, bạn gửi HTML từng phần. Trình duyệt hiển thị sớm phần có sẵn.
import { renderToPipeableStream } from 'react-dom/server';
server.get('/', (req, res) => {
const { pipe } = renderToPipeableStream(<App message="Streaming" />, {
onShellReady() {
res.setHeader('Content-type', 'text/html');
pipe(res);
}
});
});
- Giảm kích thước bundle JS: Next.js hỗ trợ code splitting, dynamic import.
- Tối ưu database và API: giảm thiểu số lần truy vấn, tăng tốc server.
Với SSR, nội dung có sẵn trong HTML. Công cụ tìm kiếm (Google) thấy nội dung mà không cần chạy JS, từ đó dễ lập chỉ mục hơn. Bạn cũng có thể đặt thẻ <title>, <meta> trên server, giúp SEO tốt.
import Head from 'next/head';
export default function Page({ post }) {
return (
<>
<Head>
<title>{post.title}</title>
<meta name="description" content={post.body.slice(0,100)} />
</Head>
<main>
<h1>{post.title}</h1>
<p>{post.body}</p>
</main>
</>
);
}
Nhờ SSR, <title> và <meta> xuất hiện ngay trong HTML trả về.
Lưu ý: SSR chạy trên server, bạn có thể kiểm tra token, cookie để quyết định nội dung hiển thị. Ví dụ, chỉ người dùng đã đăng nhập mới thấy thông tin nhạy cảm. Tuy nhiên, chú ý không đẩy thông tin nhạy cảm vào HTML. Tất cả dữ liệu trong HTML gửi xuống client là công khai. Chỉ gửi thông tin cần thiết. Thông tin nhạy cảm cần được bảo vệ (ví dụ gửi token nhạy cảm ở HTTP-only cookie chứ không nhúng vào HTML).
8. Kết luận
Server-Side Rendering mang lại sự cân bằng tuyệt vời: nội dung xuất hiện sớm, hỗ trợ SEO, và vẫn giữ được khả năng tương tác như một SPA sau khi hydrate. Mặc dù phức tạp hơn so với CSR thuần túy, nhưng với sự hỗ trợ từ các framework như Next.js, Remix việc triển khai SSR đã trở nên dễ dàng hơn nhiều.
Qua bài viết này, hy vọng bạn đã hiểu SSR, tự tin áp dụng SSR cho dự án của mình, giúp website load nhanh hơn, thân thiện với SEO hơn, và mang lại trải nghiệm tốt hơn cho người dùng.
Các bài viết liên quan:
Bài viết liên quan
Client-Side Rendering: Giải thích cơ chế hoạt động của CSR
Dec 09, 2024 • 8 min read
Vercel là gì? Hướng dẫn deploy dự án Next.js bằng Vercel
Dec 07, 2024 • 14 min read
So sánh giữa HOCs, Render Props và Hooks.
Dec 05, 2024 • 8 min read
Render Props pattern là gì? Hướng dẫn sử dụng Render Props
Dec 03, 2024 • 8 min read
HOCs Pattern là gì? Hướng dẫn triển khai Hocs Pattern trong dự án React
Dec 02, 2024 • 7 min read
Hooks Pattern là gì? Hướng dẫn áp dụng Hooks Pattern trong dự án React
Nov 28, 2024 • 11 min read