0

Cách Fetch (lấy) HTML từ máy chủ

Với sự phát triển của lập trình hướng máy chủ, khi cần lấy các template từ máy chủ, việc gửi mã HTML đến phía client trở nên cần thiết. Trong bài viết này, chúng ta sẽ xem xét các cách chính để thực hiện điều này. Tất cả các phương pháp này sẽ sử dụng JavaScript, nhưng bản chất của chúng có thể được áp dụng trong các ngôn ngữ lập trình khác.

Hãy cùng đi thẳng vào mã và xem cách có thể triển khai trong các dự án trong bài viết nagy sau đây!

Phía Client

Có một số cách để lấy HTML từ máy chủ. Tất cả chúng đều dựa trên việc gửi yêu cầu đến máy chủ. Trong JavaScript, có cấu trúc fetch giúp thực hiện điều này (không xét XMLHTTPRequest vì nó đã lỗi thời. Nếu không cần hỗ trợ trình duyệt cũ, tôi khuyên bạn không nên sử dụng nó).

1. Sử dụng thư viện bên thứ ba

Để tải HTML từ máy chủ, chúng ta có thể sử dụng HMPL, một ngôn ngữ template giúp hiển thị giao diện người dùng từ máy chủ đến client. Nó hoạt động dựa trên các yêu cầu có thể tùy chỉnh được gửi đến máy chủ và xử lý thành HTML hoàn chỉnh.

Để sử dụng, hãy cài đặt hmpl-js dưới dạng phụ thuộc và tạo một tập lệnh:

npm i hmpl-js

Sau đó, chúng ta nhập hàm compile:

import { compile } from "hmpl-js";

const templateFn = compile(
  `{{ src: "/api/getForm" }}`
);

const form = templateFn();

Kết quả:

form = {
  response: <template><h1>Contact Us</h1><form action="/submit" method="...</template>,
  status: 200
}

Ở đây, chúng ta có template, nơi lưu trữ biểu mẫu của chúng ta. Bạn cũng có thể thêm div vào chuỗi, sau đó bạn sẽ nhận được mà không có template, nhưng trực tiếp trong div.

import { compile } from "hmpl-js";

const templateFn = compile(
  `<div>{{ src: "/api/getForm" }}</div>`
);

const form = templateFn();

/*
  form = {
    response: <div><h1>Contact Us</h1><form...</div>,
    status: 200
  }
*/

Trong trường hợp này, chúng ta sẽ ngay lập tức nhận được một phần tử mà chúng ta có thể thêm vào DOM.

Ưu điểm:

  • Tái sử dụng: Có thể tái sử dụng một template đã tạo nhiều lần, giống như việc tạo ra các instance của một class.
  • Cú pháp đơn giản, dễ hiểu: HTML trong HMPL giới thiệu một đối tượng request có cú pháp tương tự như JavaScript thuần, giúp dễ dàng sao chép mã mà không lo lắng về tính tương thích.
  • Tùy chỉnh linh hoạt: Cho phép tùy chỉnh yêu cầu theo nhiều cách khác nhau. So với các dự án tương tự như HTMX, nó cung cấp khả năng kiểm soát luồng gần như hoàn toàn.
  • Nhẹ: Dung lượng chỉ khoảng 15+ KB, gần như không ảnh hưởng đến hiệu suất dự án.
  • Tương thích trình duyệt: Các API JavaScript hiện đại như fetch() được hỗ trợ rộng rãi trong trình duyệt, đảm bảo khả năng tương thích mà không cần polyfill.

Nhược điểm:

  • Phụ thuộc vào thư viện bên ngoài: Khi kết nối module, bạn sẽ thêm một số mã bổ sung vào dự án, làm tăng kích thước tổng thể.
  • Giới hạn trên trình duyệt cũ: Mặc dù được hỗ trợ rộng rãi, nhưng fetch() có thể cần polyfills cho các trình duyệt cũ, trong khi một số thư viện khác có sẵn cơ chế tương thích ngược.

2. Sử dụng JavaScript thuần (Vanilla JS)

Đầu tiên, bạn cần tạo một tệp script và thực hiện yêu cầu đến máy chủ. Mã trong tệp sẽ gần giống như sau:

main.js

fetch('/api/getForm') // URL to the HTML snippet
.then(response => {
  if (!response.ok) {
    throw new Error(`HTTP error! Status: ${response.status}`);
  }
  return response.text();
})
.then(html => {
  console.log(html);
})
.catch(error => {
  console.error('Error fetching HTML:', error);
});

Ở đây chúng ta nhận được phản hồi từ máy chủ và nếu thành công, chúng ta gọi hàm text để nhận phản hồi. Cần lưu ý rằng có mã HTTP 100, chủ yếu là chuyển hướng, vì vậy khi xử lý chúng, bạn cũng cần cẩn thận hơn và thêm xử lý lỗi.

Ưu điểm:

  • Nhẹ, không phụ thuộc thư viện: Không cần thêm thư viện hoặc framework, giúp giảm kích thước dự án.
  • Kiểm soát hoàn toàn: JavaScript thuần giúp bạn kiểm soát từng chi tiết của quá trình gửi và nhận dữ liệu, cũng như thao tác DOM theo ý muốn.
  • Tương thích trình duyệt: fetch() được hỗ trợ rộng rãi, không cần thêm polyfill cho phần lớn các trường hợp sử dụng.
  • Cơ hội học tập: Làm việc với JavaScript thuần giúp hiểu sâu hơn về các khái niệm như HTTP request, phản hồi và thao tác DOM.

Nhược điểm:

  • Mã dài dòng: JavaScript thuần thường yêu cầu nhiều đoạn mã hơn so với các thư viện như Axios hoặc framework như React.
  • Xử lý lỗi phức tạp: Cần viết thêm mã để xử lý các lỗi như mất kết nối mạng, phản hồi không hợp lệ, v.v.
  • Thiếu trừu tượng hóa: Các tác vụ như timeout, retry, hoặc quản lý yêu cầu đồng thời phải tự triển khai, dễ gây lỗi và mất thời gian.
  • Khó bảo trì: Mã JavaScript thuần có thể khó bảo trì trong các dự án lớn do tính dài dòng và thiếu mẫu chuẩn.
  • Giới hạn trên trình duyệt cũ: fetch() vẫn có thể cần polyfills nếu chạy trên các trình duyệt cũ, trong khi một số thư viện hỗ trợ sẵn điều này.

Phía Backend

Xét đến phần backend, cần lưu ý rằng trên máy khách, chúng ta phải nhận form từ đâu đó. Để làm được điều này, chúng ta có thể tạo một tuyến API, qua đó chúng ta sẽ lấy HTML từ máy chủ. Trước tiên, hãy tạo mã HTML cần gửi đến máy khách:

form.html

<h1>Contact Us</h1>
<form action="/submit" method="POST">
  <label for="name">Name:</label>
  <input type="text" id="name" name="name" required><br><br>

  <label for="email">Email:</label>
  <input type="email" id="email" name="email" required><br><br>

  <label for="message">Message:</label><br>
  <textarea id="message" name="message" rows="4" cols="50" required></textarea><br><br>

  <button type="submit">Submit</button>
</form>

Đây là một biểu mẫu liên hệ đơn giản. Sẽ thật tuyệt nếu nó có thể được chỉnh sửa trên máy chủ, sau đó trên máy khách, và không chỉ trên một trang web, mà còn, giả sử, trên nhiều trang web liên quan.

Để thực hiện điều này, hãy tạo một tuyến API, qua đó chúng ta sẽ nhận HTML từ máy chủ. Đối với phần backend, chúng ta sẽ sử dụng Node.js. Khung mà chúng ta sẽ thực hiện điều này là Express.js . Đây là một trong những khung phổ biến nhất hiện nay và hoàn hảo cho nhiệm vụ chúng ta đang giải quyết. Đầu tiên, chúng ta chỉ định bộ điều khiển sẽ xử lý HTML:

const express = require("express");
const expressRouter = express.Router();
const path = require("path");

const formController = (req, res) => {
  res.sendFile(path.join(__dirname, "../form.html"));
};

expressRouter.use("/getForm", formController);

Sau đó, bạn cần kết nối bộ điều khiển với /api, để không trộn lẫn các tuyến site thông thường với các tuyến backend. Trong express.js có một điểm nhập ứng dụng nơi mọi thứ được khởi tạo. Đây là nơi chúng ta cần nhập bộ điều khiển của mình:

app.js

const express = require("express");
const path = require("path");
const bodyParser = require("body-parser");
const cors = require("cors");
const PORT = 8000;
const app = express();
const routes = require("./routes/formController");

app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors({ origin: true, credentials: true }));

app.set(express.static(path.join(__dirname, "src")));

app.use("/api", routes);

app.listen(PORT);

Sau đó, chúng ta sẽ có một route /api/getForm trên trang web, nơi chúng ta có thể gửi yêu cầu GET. Đáp lại, chúng ta sẽ nhận được HTML.

Kết luận

Tùy vào tình huống, bạn có thể chọn cách tiếp cận phù hợp. Cách thứ hai (JavaScript thuần) giúp bạn kiểm soát hoàn toàn quy trình, nhưng không phù hợp khi làm việc với nhiều thành phần vì phải tự xây dựng logic riêng, tốn nhiều thời gian hơn.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí