[Web hoạt động như thế nào] [Phần 1] - luận về giao thức
![[Web hoạt động như thế nào] [Phần 1] - luận về giao thức](/content/images/size/w960/wordpress/2016/05/web-hoat-dong-the-nao.jpg)
Đây là bài viết đầu tiên của loạt bài ‘Học PHP – từ nâng cao đến cơ bản‘. Trong bài viết này, tôi muốn trình bày về kiến thức cực kì cơ bản về web hoạt động như thế nào ở mức cần thiết cho các lập trình viên. Nó hữu ích cho tất cả các bạn lập trình viên nói chung, chứ không chỉ riêng PHP. Đồng thời, tôi nghĩ nó cũng là kiến thức cần thiết cho cả các bạn tester, product manager, business analyst trong mảng IT.
Nhiều bạn sẽ thắc mắc: em đi làm mấy năm về phát triển web rồi, anh đặt câu hỏi này với em chỉ bằng thừa. Hãy tin và đọc tiếp bài này. Tuy nhiên, tôi nói trước rằng nó sẽ rất dài. Nó cũng đòi hỏi bạn phải đọc thêm khá nhiều vì tôi chỉ dẫn dắt những vấn đề bạn cần quan tâm chứ không thể đi vào chi tiết được.
Nền tảng về giao thức và đặc tả
Các nền tảng về giao thức
Web là một mô hình client – server được hoạt động dựa trên giao thức HTTP. Trong mô hình này, client chính là trình duyệt mà ta sử dụng. Server chính là máy chủ đóng vai trò trả lời cho yêu cầu ta gửi đi từ client.
Ở mô hình client server, máy chủ đóng vai trò bị động. Nó chỉ có thể trả lời client khi có 1 yêu cầu được gửi đến, chứ không thể broadcast dữ liệu của mình cho tất cả các client kết nối vào nó khi có sự thay đổi cần cập nhật.
Bạn sẽ hỏi tôi rằng: vậy các ứng dụng chat và notification hoạt động theo cơ chế nào. Câu này tôi sẽ trình bày ở một bài viết khác. Hãy học và xuất phát từ những điều căn bản nhất. Đi thật chậm và nghĩ thật chắc.
Ngoài 2 tiền đề chính là mô hình client server và giao thức HTTP, web còn hoạt động phụ thuộc trên một số nền tảng khác về giao thức:
- DNS: cơ chế phân giải từ tên miền để lấy ra IP của máy chủ
- TCP/IP: là nền tảng giao thức ở tầng network.
Giao thức nói chung là một loại đặc tả quy định cách thức giao tiếp giữa các hệ thống. Tuy nhiên, web còn hoạt động dựa trên thêm một số đặc tả nữa để giải quyết cho các vấn đề dưới đây:
- Đặc tả ngôn ngữ HTML: sử dụng để tạo ra markup của 1 response cho 1 web page. HTML dùng để đặc tả về cấu trúc ngữ nghĩa của 1 nội dung trang web.
- Đặc tả về CSS: CSS là đặc tả để quy định việc hiển thị tài liệu HTML lên trình duyệt.
- Đặc tả ECMA script: ECMA script là đặc tả của ngôn ngữ Javascript (JS). JS được sử dụng để lập trình ở phía client side cho việc tương tác với người sử dụng.
- Đặc tả WAI về web accessibility (https://www.w3.org/WAI/): web được sử dụng để phục vụ cho tất cả mọi người. Trong đó, có cả những người khiếm thính, khiếm thị, mù màu. Chính vì vậy, đặc tả về Web accessibility sẽ giúp bạn hiểu rõ hơn về cách để hiện thực website của mình sao cho những người khiếm thính, khiếm thị vẫn có thể sử dụng được.
Tôi không tham vọng trình bày tất cả các kiến thức về toàn bộ những đặc tả này trong bài viết này vì nó vượt qua phạm vi của bài viết và cũng không đủ thời gian để trình bày hết. Điều tôi muốn bạn hình dung là: web hoạt động dựa trên một tập các giao thức và đặc tả. Bạn cần cái nào cho mục đích gì thì nên tìm hiểu sâu về đặc tả hay giao thức đó.
Đôi chút về HTTP
HTTP – Hybertext Transfer Protocol (ref) là giao thức quy định cách nói chuyện giữa client và server để truyền nhận ‘siêu văn bản’. Dịch là siêu văn bản để thống nhất cách gọi trong bài viết. Siêu văn bản (Hybertext) được định nghĩa là văn bản có cấu trúc và liên kết.
Cũng nên nói qua một chút về lịch sử của giao thức HTTP. Ban đầu, Tim Berners-Lee (có thể gọi ông là ông tổ của web) dự định tạo ra một loại đặc tả để liên kết các văn bản với mục đích số hoá những tài liệu của các trường đại học. Ngôn ngữ này chính là HTML. Tuy nhiên, không dừng lại ở đó – ông phát triển thêm giao thức HTTP để cho phép việc truyền nhận những tài liệu HTML qua network. Nhờ ơn của ông, mà ta có web hoạt động như ngày nay.
Giao thức HTTP quy định:
- Cấu trúc của request và response
- Ngữ nghĩa của các request method, response code và quy định về hành xử để xử lý cho một số điều kiện xảy ra trong quá trình giao tiếp.
- Cơ chế authentication
- Quy định về caching
HTTP là giao thức stateless:
Stateless có nghĩa là không có trạng thái – xử lý xong một lần rồi thôi cho 1 request. Trong toàn bộ đặc tả của HTTP không hề đòi hỏi server phải lưu giữ thông tin user để biết trạng thái cuả họ trong nhiều lần request.
Vậy làm sao mình giữ được trạng thái của user trên nhiều lần request?
Trên thực tế, đây là một nhu cầu tất yếu với rất nhiều ứng dụng web. Ví dụ: Bạn phải biết user đã login chưa, trước đó họ đã đặt sản phẩm nào vào giỏ hàng, số lượng bao nhiêu ….
Để vẫn đảm bảo được HTTP protocol, người ta implement một khái niệm gọi là: session ở tầng application/web server. Session là vùng dữ liệu ở server chứa thông tin về trạng thái của một user khi họ tương tác trên web. Ở client sẽ phải giữ một biến Session ID để ánh xạ với vùng dữ liệu của user trên máy chủ. Thường Session ID sẽ được truyền nhận giữa client và server thông qua biến lưu trữ trong cookie hoặc các hidden variable trên form.
Mỗi application/web server có cách implementation riêng của mình về việc lưu trữ session ID. Vì vậy, bạn sẽ thấy biến này có những tên gọi khác nhau tuỳ theo bạn sử dụng web server nào, kĩ thuật nào. Nếu thích, bạn cũng có thể tự implement cơ chế lưu trữ session riêng của mình. Tuy nhiên, về cơ bản – session ID vẫn được lưu giữ ở cookie (phía client). Điều này giải thích tại sao khi bạn xoá cache browser và cookie, bạn sẽ bị bắt đăng nhập lại ở nhiều website.
(Ghi chú: mình phỏng vấn khá nhiều anh Technical Architect – có bạn đi làm đã hơn 10 năm với câu hỏi đơn giản là session lưu trữ ở đâu. Vậy mà cũng nhận được câu trả lời được là lưu ở browser. Đi sông đi biển không chết, thì đừng để bị sụp hầm vì những mảng hổng về kiến thức như vậy).
Bạn cần học gì về HTTP:
- Bạn cần nắm những method của HTTP – hiểu rõ khi nào nên dùng method nào.
- Những HTTP code căn bản và hiểu khi nào mình nên return HTTP code nào ở phía server.
- Hiểu rõ các trạng thái chuyển tiếp và workflow HTTP xử lý 1 request.
TCP/IP
HTTP về mặt bản chất là một giao thức dựa trên TCP/IP. Nói nôm nà là vầy, TCP/IP quy định một level sâu hơn về cách giao tiếp ở tầng network bao gồm: cách gửi nhận các gói dữ liệu + định tuyến và tổng hợp dữ liệu ở đầu nhận. Thật ra TCP/IP là bộ đôi của 2 giao thức: TCP và IP. Bạn có thể đọc thêm về TCP/IP ở đây: https://en.wikipedia.org/wiki/Internet_protocol_suite
Khi nói đến giao tiếp TCP/IP là ta nói đến việc giao tiếp qua port. Máy tính giao tiếp với nhau phần lớn đều dựa trên các giao thức truyền nhận dữ liệu qua port. Giao thức web thường hoạt động ở port 80. Tuy nhiên, bạn hoàn toàn có thể quy định một port bất kì để nói chuyện qua giao thức HTTP với bên ngoài bằng cách cấu hình web server của bạn.
Mỗi web server để nói chuyện với bên ngoài nó cần 1 public IP. IP là định danh của một thiết bị để những thiết bị, ứng dụng khác giao tiếp với nó qua network. IP ở các server thường phải là IP tĩnh. IP giống như địa chỉ nhà của bạn. Nếu IP thay đổi liên tục (IP động) thì không ai giao tiếp được với bạn cả vì bạn chuyển nhà liên tục.
Việc cấp phát địa chỉ IP của một thiết bị và ràng buộc IP là tĩnh hay động được thực hiện qua một giao thức gọi là DHCP. Nói nôm na, mỗi lần bạn bật máy tính lên – nó sẽ hỏi DHCP server: cho tui 1 địa chỉ IP đi. DHCP server sẽ cấp IP cho thiết bị của bạn. DHCP server có thể được cấu hình ở tầng network ở cty của bạn hoặc của ISP (nhà cung cấp dịch vụ Internet).
DHCP cũng là 1 giao thức dựa trên nền tảng UDP (một giao thức ngang hàng với TCP – tuy nhiên nó không cung cấp sự tin cậy về đảm bảo thứ tự của các gói tin khi tổng hợp như TCP). Bạn nên đọc để hiểu thêm sự khác nhau giữa TCP và UDP nếu quan tâm. Trên thực tế, nếu bạn không làm việc nhiều ở tầng network thì hiểu về khái niệm của TCP và UDP là đủ. Port mà DHCP server mở để nhận tín hiệu là port 67. Port của DHCP client (thiết bị cần cấp IP) là port 68.
Đôi chút kiến thức về port và tường lửa (firewall)
Như đã nói ở trên, mọi chương trình ở thời điểm hiện tại đều giao tiếp với nhau qua port (trừ các loại ứng dụng sâu hơn ở tầng network hoặc phần cứng nhúng). Một số nguyên tắc về port mà bạn cần phải biết:
- Một chương trình có thể chiếm 1 hoặc nhiều port để nhận tín hiệu từ thế giới bên ngoài. Tuy nhiên 1 port nhận tín hiệu chỉ có thể được sử dụng bởi 1 chương trình duy nhất. Port giao tiếp này để nhận tín hiệu, nên người ta gọi nó là: incoming port (port đi vào, hay còn gọi là port nhận). Ví dụ: web server thường mở port 80, FTP server thường mở port 21, SSH thường mở port 22, MySQL thường mở port 3306… Nếu 1 port đã bị chiếm bởi chương trình khác thì thường các chương trình sử dụng port này để nhận tín hiệu khi start lên sẽ báo lỗi và dừng ngay.
- Ở trên máy tính, nếu bạn muốn truy xuất ra ngoài để sử dụng dịch vụ liên kết với port nào đó – thì port đó phải được mở ra ngoài để giao tiếp. Trường hợp này người ta gọi là: outgoing port (port đi ra). Ví dụ: trên laptop của bạn – nếu muốn duyệt web, thì port 80 phải được cho phép đi ra ngoài. Nếu bạn duyệt 1 website với đường dẫn: http://example.com:8080 -> có nghĩa là giao thức HTTP để truy cập website này phải được giao tiếp qua port 8080. Nếu ai cũng vào được, chỉ duy nhất bạn không truy cập được – thì có nghĩa là port 8080 không được mở để đi ra ngoài trên máy bạn (hoặc ở trên network của công ty bạn).
- Một port có thể đồng thời được cấu hình để cho phép nhận tín hiệu hoặc từ gửi tín hiệu. Việc cấu hình này thường được thiết lập ở tường lửa trên máy bạn hoặc ở proxy của công ty bạn/ ISP (nhà cung cấp dịch vụ).
- Trong quá trình giao tiếp, tín hiệu đi vào – đi ra có thể sẽ đi qua rất nhiều tầng tường lửa. Tầng gần bạn nhất là máy tính của bạn. Tín hiệu sau khi qua khỏi tường lửa của hệ điều hành còn phải đi qua tường lửa của mạng cục bộ (LAN), tường lửa của ISP, WAN…
Domain là gì và cách thức nó hoạt động
Vì web hoạt động dựa trên HTTP. HTTP lại dựa trên nền tảng TCP/IP của network. Do đó, máy tính của bạn và máy chủ chỉ giao tiếp và biết đến nhau qua địa chỉ IP. Tuy nhiên, bạn không thể bắt mọi người trên thế giới nhớ đến website của bạn qua IP vì nó quá khó nhớ. Vì lẽ đó, người ta tạo ra một khái niệm mới là Domain.
Domain quy định một ánh xạ / một cách truy vấn ra IP của máy chủ dựa vào một cái tên dễ nhớ. Quá trình phân giải từ domain ra IP thật ra là một quá trình khá phức tạp. Tôi sẽ tóm lược một số bước căn bản của quá trình phân giải domain này trong nội dung dưới đây. Giả sử người dùng gõ vào web browser một địa chỉ: http://www.example.com và click enter. Quá trình phân giải domain sẽ bắt đầu như sau:
- Bước 1 – hỏi browser cache: Trước tiên, browser sẽ kiểm tra trong bộ nhớ cache của nó để xem domain này đã được phân giải thành IP chưa. Nếu có, nó sẽ trả lại kết quả IP mà nó đã cache. Nếu không có, nó sẽ hỏi hệ điều hành.
- Bước 2 – hỏi cache DNS của hệ điều hành: Hệ điều hành nhận được chuỗi domain truy vấn, nó cũng sẽ tìm trong bộ nhớ cache và xem trước đây nó đã có lưu IP của domain này chưa. Nếu có thì trả về kết quả. Nếu không nó sẽ thực hiện một giao thức DNS query qua DNS port đến ISP (nhà cung cấp Internet của bạn). Hiểu nôm na là DNS query này sẽ được gửi ra network mà bạn đang kết nối. Lưu ý một điều cực kì quan trọng: bản thân DNS query cũng là một giao thức dựa trên TCP/IP nên nó cũng sẽ giao tiếp qua port. DNS port thường là port 53. Do đó, trong vài trường hợp nếu bạn vô tình chặn port đi ra (outgoing port) của máy tính là 53, bạn sẽ không thể query được bất cứ domain nào. Bạn có thể tham khảo thêm về DNS port ở đây.
- Bước 3 – query cache của các DNS server: Khi DNS query được gửi ra network, nó sẽ query ở các DNS servers. DNS server có thể được cấu hình ở mạng nội bộ công ty của bạn hoặc nó nằm ở ISP (nhà cung cấp dịch vụ). Các DNS server này cũng tìm trong vùng dữ liệu cache của mình xem có kết quả IP nào đã lưu cho domain này không. Nếu có, nó sẽ trả lại kết quả. Nếu không, nó sẽ thực hiện bước kế tiếp.
- Bước 4 – hỏi Root name server: Trong trường hợp DNS server không có kết quả, nó sẽ đi hỏi các root name server. Hiện tại có 13 Root name server trên toàn thế giới. Name server là máy chủ chuyên biệt để thực hiện các truy vấn về domain name. Name server có thể không biết câu trả lời chi tiết, nhưng nó chứa thông tin của các name server khác biết câu trả lời. Các root name servers chỉ lưu giữ thông tin các TLD server (Top level domain server). Mỗi Top Level Domain (TLD), ví dụ: .com, .org … đều có 1 tập TLD Name server của nó. Quay lại ví dụ của chúng ta là: www.example.com – tại bước này Root name server sẽ tìm ra danh sách các TLD name server của .com . và trả ra để thực hiện bước tiếp theo.
- Bước 5 – Hỏi TLD name server: các TLD name server sẽ phân giải phần kế tiếp của www.example.com là: example.com. TLD name server lưu trữ các name server chịu trách nhiệm chứa toàn bộ thông tin chi tiết của domain – còn gọi là Authoritative name server. Dựa vào chuỗi (example.com), các TLD name server sẽ truy vấn ra Authoritative name server tương ứng.
- Bước 6 – hỏi Authoritative name server: Thông tin chi tiết của một domain được lưu trữ dưới các DNS records trên Authoritative name server. Có rất nhiều loại DNS record, mỗi loại giữ một số thông tin khác nhau. Tôi sẽ trình bày về các loại DNS record liên quan trong phần kế tiếp. Trong ngữ cảnh của chúng ta là sub domain (www.example.com), Authoritative name server sẽ trả lại một trong 2 loại record: A record hoặc CNAME record.
- A record sẽ lưu giữ ánh xạ chính xác từ full domain name liên kết với 1 IP.
- CNAME record lại là một tham chiếu từ một sub domain qua một domain name khác. CNAME là trường hợp phức tạp. Để đỡ rối, tôi sẽ trình bày sâu hơn cho trường hợp phân giải IP của sub domain qua CNAME ở phần tiếp theo của ‘Các loại DNS record’. Tạm thời ở bước này, bạn nên chấp nhận là ta lấy được IP của domain qua A record.
- Bước 7 – nhận kết quả và lưu trữ cache cho DNS record ở các DNS server: A DNS record sẽ được lưu trữ lại để cache ở các DNS server. Mỗi DNS record có quy định một khoảng thời gian sống (time to live). Nôm na, là khoảng thời gian hiệu lực được cache trên các DNS server. Nếu thời gian này expired, các DNS server phải thực hiện lại quá trình query của mình từ bước 4 đến bước 6 để cập nhật thông tin mới nhất của A record này.
- Bước 8 – nhận kết quả trên máy tính: khi kết quả được trả lại cho máy tính của bạn, DNS record sẽ được cache ở hệ điều hành và browser.
Toàn bộ quá trình này được thực hiện vỏn vẹn trong vài đến vài chục ms.
Quá trình phân giải domain là một quá trình cực kì quan trọng. Bạn cần phải đọc đi, đọc lại toàn bộ quá trình này đến khi hiểu thật rõ. Hiểu rõ DNS hoạt động thế nào sẽ giúp bạn rất nhiều trong quá trình xử lý các vấn đề cho các ứng dụng web. Dưới đây là một vài câu hỏi mà bạn sẽ nên tìm hiểu để vận dụng và nắm rõ hơn bản chất của quá trình này:
- Tôi viết 1 ứng dụng web và muốn nó chạy với một domain giả (greatidea.dev) ở máy tính của tôi để test. Vậy tôi cần cấu hình nó ở đâu?
- Sau khi test ứng dụng web (greatidea.dev) trên máy local của mình – tôi muốn test nó trên các thiết bị di động khác trong cùng mạng cục bộ. Tôi có thể cấu hình và xử lý như thế nào?
- Tôi gửi website của tôi cho 1 khách hàng và đã cấu hình cho webserver chạy ở port 8080 (http://greatidea.com:8080). Ai cũng chạy được, chỉ có 1 người không chạy được. Tôi nên bắt đầu quá trình debug vấn đề này như thế nào?
- Rất nhiều người than phiền là thời gian phân giải DNS cho website http://example.com lâu quá. Là một lập trình viên đã phát triển website này, tôi nên làm gì?
Các loại DNS record liên quan đến phân giải domain
Có khá nhiều loại DNS record. Bạn có thể tham khảo chi tiết tại wikipedia ở đây. Trong khuôn khổ bài viết này, tôi chỉ trình bày một số loại record chính liên quan đến vấn đề phân giải IP cho domain. Hiểu rõ các loại DNS record này sẽ giúp bạn biết cách cấu hình DNS khi mua domain và hosting.
- A record: như trên đã có đề cập, A record lưu trữ domain và IP mà nó liên kết. A record dùng cho IPv4. AAAA record dùng cho IPv6. Câu hỏi tìm hiểu thêm: IPv4 khác IPv6 điểm nào?
- CNAME record: là định danh của một sub domain để trỏ đến một domain khác. Ví dụ: bạn hoàn toàn có thể cấu hình cho sub domain www.excitingthing.com trỏ đến google.com thông qua record CNAME. Lưu ý: CNAME record không thể sử dụng để cấu hình cho TLD (Top level domain), vd: excitingthing.com. Nếu quá trình phân giải Domain gặp CNAME record ở Authoritative Name server, nó sẽ query tiếp cho giá trị domain name tham chiếu này từ bước đầu tiên của quá trình phân giải Domain để tìm ra A record chứa IP.
- NS record: dùng để uỷ quyền việc phân giải domain name qua một name server khác. Khi bạn mua một domain name của một nhà cung cấp (Domain registra), mặc định họ sẽ có Authoritative name server trên hạ tầng của họ (hoặc thuê) để lưu trữ các DNS records cho domain name của bạn. Trong vài tình huống đặc biệt, bạn không muốn việc phân giải DNS record được thực hiện qua các name server của nhà cung cấp domain nữa mà thông qua một name server của bên thứ ba khác (hoặc của bạn). Ở ngữ cảnh này, ta có 2 lựa chọn:
- Chuyển toàn bộ name server của domain của nhà cung cấp cũ qua name server mới. Quy trình này đòi hỏi vài thủ tục nho nhỏ để xác nhận quyền sở hữu domain của bạn. Nói chung là khá dài để giải thích ở đây. Bạn có thể tìm hiểu về quy trình này nếu hứng thú.
- Tạo ra 1 NS record trong các DNS records trong name server của nhà cung cấp cũ để chỉ định Name server mới sẽ được uỷ quyền để phân giải domain.
Tôi sẽ chia sẻ vài trải nghiệm về các loại DNS record này trong vài tình huống tôi đã gặp qua dưới đây:
Trường hợp 1 – sử dụng CNAME: Trước đây tôi làm việc với hạ tầng của AWS để cung cấp nền tảng về hosting cho 1 tập đoàn toàn cầu về mảng khách sạn cao cấp. Hạ tầng của họ cần 1 giải pháp cân bằng tải sử dụng ELB (giải pháp load balancing của AWS). Trong giải pháp load balancing của AWS, họ sẽ trả ra cho ta một domain name đại diện cho load balancer chứ không phải 1 IP tĩnh (ví dụ: elb-1234-aws.com). Vì vậy, nếu website của họ là: www.example.com – thì ta sẽ cần cấu hình 1 CNAME record cho www (sub domain của example.com) trỏ tới domain name của Amazon Load balancer.
Trong trường hợp họ muốn website hoạt động thông qua top level domain (example.com), thì ta không thể cấu hình CNAME được vì CNAME không hoạt động với Top level domain. Trong trường hợp đó, phải thiết lập một proxy server. Tuy nhiên, nó không nằm trong phạm vi bài viết này nên tôi không muốn trình bày chi tiết.
Trường hợp 2 – sử dụng NS record: vì tập đoàn này đã mua domain trước đây của một nhà cung cấp và quản lý domain khá nổi tiếng là CSC. Tuy nhiên, chúng tôi không muốn phải gọi điện cho CSC vào lúc nửa đêm khi website go live vì họ làm việc lệch múi giờ. Để có quyền điều khiển các DNS record hoàn toàn, chúng tôi yêu cầu CSC delegate việc phân giải domain về name server của Amazon. Trong tình huống này, ta chỉ cần gửi cho họ name server ta đang có và yêu cầu cấu hình NS record trỏ về name server mới là xong.
Những câu hỏi để bạn tìm hiểu thêm:
- Mình muốn đăng kí làm một nhà phân phối domain. Mình sẽ cần đăng kí với ai? Hiệp hội nào quản lý các nhà phân phối d0main?
- Lúc trước, có một bác chơi vui đăng kí mua domain: com.vn – vậy mà vẫn được 1 nhà phân phối domain ở ViệtNam cung cấp. Tại sao domain kiểu com.vn lại không được phân phối?
- Tên của domain cần phải tuân theo những ràng buộc gì?
Kết của phần đầu – luận về giao thức
Đến đây tôi tạm kết thúc phần đầu tiên về những giao thức chính được sử dụng để làm cho web hoạt động. Trong các phần kế tiếp, tôi sẽ trình bày thêm 2 chủ đề:
- Luận về trình duyệt
- Luận về web server.
Thực tế, web hoạt động là dựa trên 3 thành phần: client (trình duyệt), web server và giao thức để cả hai nói chuyện. Ở bài viết đầu tiên này, tôi đã trình bày khá tổng quát những kiến thức bạn cần phải tìm hiểu về các giao thức liên quan. Hẹn gặp lại trong các bài viết kế tiếp.
Trân trọng.