Menu

Kiểm tra tại API: nên chặn ở máy khách hay máy chủ

Kiểm tra tại API cần chia đúng trách nhiệm: máy khách cho phản hồi tức thì, máy chủ là nơi quyết định. Bài này nói rõ ba tầng không được trộn và vì sao số thật không được rơi vào nhật ký hay dữ liệu thử.

Đăng ngày

  • kiểm tra tại API
  • tầng ứng dụng
  • dữ liệu thử

Kiểm tra tại API là câu hỏi về việc đặt phép kiểm tra ở đâu trong một hệ thống có hai phía: ứng dụng chạy trên thiết bị người dùng và dịch vụ chạy trên máy chủ. Câu trả lời ngắn là cả hai, nhưng mỗi phía làm một việc khác nhau và không được phép thay thế nhau. Đọc hết bài này, bạn sẽ biết việc gì chỉ nên chạy ở máy khách, việc gì chỉ được chạy ở máy chủ, vì sao ba tầng kiểm tra không được trộn thành một, và vì sao số thật của người dùng không bao giờ nên xuất hiện trong nhật ký hay trong bộ dữ liệu thử.

Vì sao cần chặn ở cả hai phía?

Máy khách là phía duy nhất tương tác trực tiếp với người dùng, nên chỉ ở đó mới có thể đưa ra phản hồi tức thì ngay khi người dùng vừa nhập xong. Nếu mọi phép kiểm tra đều phải chờ một vòng gọi mạng, biểu mẫu sẽ có độ trễ rõ rệt, và độ trễ đó tệ nhất ở đúng những nơi có kết nối yếu, tức là nơi người dùng cần phản hồi nhất.

Máy chủ là phía duy nhất có thẩm quyền, vì nó là nơi dữ liệu được lưu và là nơi mọi yêu cầu có thể đến từ nhiều nguồn khác nhau. Một phép kiểm tra chỉ chạy ở máy khách không có giá trị bảo vệ nào, vì bất kỳ ai cũng có thể gửi yêu cầu trực tiếp tới dịch vụ mà bỏ qua toàn bộ giao diện.

Vì vậy vai trò của hai phía khác nhau về bản chất chứ không chỉ khác nhau về mức độ. Máy khách giúp người dùng sửa nhanh và giúp hệ thống giảm tải. Máy chủ quyết định dữ liệu nào được chấp nhận. Nhầm hai vai trò này là nguồn gốc của hai lỗi đối xứng: hoặc là hệ thống không bảo vệ được gì, hoặc là hệ thống làm người dùng chờ đợi một cách vô ích.

Việc gì nên chạy ở máy khách

Máy khách phù hợp với những phép kiểm tra chạy được cục bộ, không cần dữ liệu bên ngoài, và cho cùng một kết quả mỗi lần chạy. Đây chính là nhóm phép kiểm tra cấu trúc: chuẩn hóa chuỗi, đối chiếu tập ký tự, đối chiếu độ dài, và nếu có thuật toán công khai thì tính chữ số kiểm tra.

  • Hiển thị kết quả ngay khi người dùng rời khỏi ô nhập, không chờ tới lúc gửi biểu mẫu.
  • Không gửi yêu cầu lên máy chủ cho những chuỗi đã chắc chắn sai định dạng. Mỗi yêu cầu như vậy là một lượt gọi mạng bị tiêu tốn mà không đem lại thông tin gì.
  • Không khẳng định bất cứ điều gì vượt quá cấu trúc. Máy khách không có dữ liệu để biết một con số có thật hay không, nên nó cũng không nên nói.
  • Giữ thông báo lỗi ở mức cụ thể. Nếu máy khách biết chữ số nào bị lệch, hãy nói ra, vì không có gì để giữ lại cho máy chủ ở điểm này.
  • Không lưu giá trị người dùng nhập vào bộ nhớ đệm lâu dài trên thiết bị, vì đây là dữ liệu định danh và không có lý do gì để giữ lại sau khi biểu mẫu đã đóng.

Một điểm cần nhấn mạnh: việc máy khách chạy phép kiểm tra không làm cho phép kiểm tra ở máy chủ trở nên thừa. Nó chỉ làm cho phần lớn lỗi bị chặn trước khi tới máy chủ.

Việc gì chỉ được chạy ở máy chủ

Máy chủ phải chạy lại toàn bộ những phép kiểm tra cấu trúc, bất kể máy khách đã chạy chúng hay chưa. Lý do rất đơn giản: kết quả từ máy khách là dữ liệu do phía ngoài gửi tới, và mọi dữ liệu từ phía ngoài đều phải được xác minh lại ở nơi có thẩm quyền.

Ngoài ra, máy chủ là nơi duy nhất chạy được những việc cần tài nguyên mà máy khách không có. Những việc đó gồm ba nhóm chính.

  • Tra cứu ở nguồn dữ liệu bên ngoài để hỏi xem một con số có thật hay không. Việc này cần thông tin xác thực, có thể bị giới hạn tần suất, có thể mất vài giây, và có thể thất bại hoàn toàn.
  • Áp những quy tắc nghiệp vụ phụ thuộc vào trạng thái của hệ thống, ví dụ một con số đã được dùng cho bản ghi khác hay chưa.
  • Ghi lại nhật ký có kiểm soát và thống kê tần suất, để biết loại lỗi nào đang phổ biến và từ nguồn nào.

Việc tra cứu ở nguồn dữ liệu bên ngoài cần một thiết kế riêng, vì nó có thể thất bại vì lý do không liên quan tới dữ liệu. Khi nó thất bại, kết quả đúng không phải là không hợp lệ, mà là chưa xác minh được. Nếu hệ thống gộp hai tình huống này, người dùng sẽ bị từ chối bởi một lỗi hạ tầng mà họ không thể sửa được.

Ba tầng không được trộn: định dạng, thuật toán, tra cứu

Ba tầng này trả lời ba câu hỏi rất khác nhau, và chi phí của chúng chênh nhau rất nhiều. Tầng định dạng chạy trong vài phần nghìn giây. Tầng thuật toán cũng vậy, vì nó chỉ là một vòng lặp trên chuỗi ký tự. Tầng tra cứu thì phụ thuộc vào mạng và vào hệ thống của bên thứ ba, nên nó chậm hơn nhiều bậc và có thể hỏng.

Tầng Câu hỏi được trả lời Nơi chạy Chi phí và độ tin cậy
Định dạng Chuỗi có đúng tập ký tự và độ dài không Cả hai phía Rất nhanh, luôn sẵn sàng
Thuật toán Chữ số kiểm tra có khớp phần thân không Cả hai phía Rất nhanh, luôn sẵn sàng
Tra cứu Con số này có tồn tại và còn hiệu lực không Chỉ máy chủ Chậm, có thể bị giới hạn, có thể thất bại

Việc trộn ba tầng thành một hàm duy nhất thường bắt đầu từ một lý do rất hợp lý là cho gọn, và kết thúc bằng một hệ thống không nói được vì sao nó từ chối một yêu cầu. Khi đã tách rời, mỗi tầng có thể thay đổi, gỡ lỗi và tắt đi độc lập.

Một quy tắc thực hành hữu ích: nếu một phép kiểm tra có thể thất bại vì lý do không liên quan tới dữ liệu người dùng nhập, nó phải nằm ở tầng riêng và phải có đường lui rõ ràng. Bạn có thể quan sát cách một công cụ trình bày riêng kết quả tính toán và kết quả tra cứu trên công cụ kiểm tra số của trang này.

Vì sao số thật không được xuất hiện trong nhật ký?

Vì nhật ký là nơi thông tin tồn tại lâu nhất và được đọc bởi nhiều người nhất. Một con số định danh đi vào nhật ký sẽ bị nhân bản qua mọi bản sao lưu, mọi công cụ theo dõi và mọi bảng điều khiển. Sau đó không ai còn kiểm soát được nó nằm ở đâu.

Vấn đề này thường không đến từ quyết định rõ ràng nào, mà đến từ thói quen ghi lại toàn bộ giá trị đầu vào để tiện gỡ lỗi. Cách xử lý là ghi lại những gì cần thiết cho việc gỡ lỗi mà không ghi giá trị gốc: trạng thái kết quả, tên hệ thống đã dùng, vị trí ký tự bị lệch, và một mã định danh để đối chiếu với bản ghi thật khi cần.

Điều tương tự áp dụng cho dữ liệu thử. Khi viết kiểm thử cho tầng kiểm tra, hãy dùng những giá trị được dựng riêng cho mục đích đó, và ghi rõ trong tệp dữ liệu rằng chúng là giá trị giả. Không lấy số thật của khách hàng rồi đổi một hai chữ số, vì cách làm đó vẫn đưa dữ liệu thật vào kho mã nguồn và vẫn có thể trùng với một con số đang tồn tại.

Phần dành cho nhà phát triển: hợp đồng lỗi giữa hai phía

Điều đáng đầu tư nhất ở đây không phải là thuật toán mà là hợp đồng giữa máy khách và máy chủ về việc mỗi bên trả về loại kết quả nào. Khi hợp đồng này rõ ràng, hai phía có thể được phát triển và kiểm thử độc lập.

  • Định nghĩa một tập trạng thái dùng chung, và dùng đúng cùng một tập ở cả hai phía. Trạng thái chỉ định dạng phải có mặt trong tập đó, nếu không nó sẽ bị gộp vào một trạng thái khác.
  • Đặt tên trường trong phản hồi theo trạng thái, không theo câu thông báo. Câu thông báo sẽ thay đổi theo ngôn ngữ và theo giao diện, còn trạng thái thì ổn định.
  • Phân biệt lỗi dữ liệu với lỗi hạ tầng bằng mã khác nhau. Người dùng có thể sửa lỗi thứ nhất, còn lỗi thứ hai thì không.
  • Cho phép máy chủ từ chối một giá trị mà máy khách đã chấp nhận, và ghi lại việc đó. Đây là dấu hiệu cho thấy hai phía đang dùng hai phiên bản quy tắc khác nhau.
  • Kiểm thử hợp đồng bằng cách gửi thẳng yêu cầu tới máy chủ, bỏ qua giao diện. Nếu cách này nhận được kết quả khác với khi đi qua giao diện, lớp bảo vệ của bạn nằm sai chỗ.
  • Đừng để tầng tra cứu chặn luồng nhập liệu. Hãy trả về kết quả sớm cho những gì kiểm tra được cục bộ, và xếp việc tra cứu vào một bước riêng có thể chạy sau.
  • Ghi lại phiên bản bộ quy tắc đã dùng cho mỗi phản hồi. Khi có tranh chấp về một kết luận, đây là thứ duy nhất giúp tái hiện lại phán đoán cũ.

Với một hợp đồng như vậy, việc thay đổi quy tắc ở máy chủ không còn là một sự kiện đáng sợ cho đội phát triển ứng dụng.

Bước tiếp theo

Hãy thử gửi thẳng một yêu cầu tới dịch vụ của bạn, bỏ qua giao diện, với một giá trị cố tình sai, và xem hệ thống có chặn được hay không. Nếu nó chấp nhận, lớp bảo vệ của bạn đang nằm ở phía không có thẩm quyền. Để hiểu những trạng thái mà hợp đồng này cần truyền đi, bài kiểm tra số: ký tự, độ dài và chữ số kiểm tra mô tả bốn kết luận và cách phân biệt chúng; còn bài quy trình kiểm tra hàng loạt nhiều số một lúc nói về trường hợp cùng logic đó phải chạy trên cả một tệp dữ liệu. Nếu hệ thống của bạn xử lý địa chỉ và số điện thoại ở nhiều nước, bài kiểm thử địa chỉ và số điện thoại quốc tế có thêm ví dụ cùng chủ đề.

Mọi giá trị số được nhắc tới trong bài chỉ là ví dụ dựng sẵn cho việc giải thích cách phân tầng; chúng không phải số thật của bất kỳ người dùng, tài khoản hay tổ chức nào, không được đưa vào nhật ký hay dữ liệu thử, và không được dùng để mạo danh hay để khẳng định một con số là dùng được.

Đọc tiếp

Bài viết về Kiểm Tra CCCD