→ From Coder to Shipper
From Coder to Shipper · Nền tảng web

Flask / HTTP / curl

Cuộc hội thoại giữa trình duyệt và server, đi sâu: HTTP thực sự là gì, một request biến thành response ra sao, Flask biến hàm Python thành trang web thế nào — và cách kiểm thử tất cả bằng curl.

← / → để chuyển slide · chuyển EN/VI bên dưới

Toàn cảnh

Web là cuộc hội thoại hai chiều

HTTP (Hypertext Transfer Protocol) điều hành mọi thứ. Đổi lượt nghiêm ngặt: client nói trước, server trả lời một lần, và lượt chơi kết thúc.

🌐 Client

Trình duyệt, app điện thoại, curl… tức là bạn. Phía duy nhất được quyền mở cuộc hội thoại.

① REQUEST GET /about + headers ▶
② RESPONSE 200 OK + HTML ◀

🖥 Server

Một chương trình lắng nghe trên một cổng (80/443). Nó không bao giờ chủ động — chỉ trả lời.

một request → một response → xong · mỗi cú click, mỗi lần refresh, mỗi API call đều đúng là thế này

Toàn cảnh

HTTP tồn tại vì sao

Trước HTTP, mỗi cặp client–server tự phát minh phương ngữ riêng. HTTP là phương ngữ duy nhất mà tất cả cùng thống nhất.

Một ngôn ngữ chung

Hàng tỷ client và server — do nhiều người xây, bằng nhiều ngôn ngữ code — thống nhất một bộ quy tắc duy nhất. HTTP là thỏa thuận đó.

Hai phía, vai trò nghiêm ngặt

Client hỏi, server trả lời. Vai trò không bao giờ hoán đổi — chỉ một quy tắc đó khiến web có thể dự đoán ở quy mô toàn cầu.

Stateless — không nhớ

Mỗi trao đổi là một cuộc hội thoại mới; server quên bạn ngay khi response được gửi đi. Cookie và session là chiêu trò giả lập bộ nhớ.

Bên trong là text thuần

Request và response chỉ là text có định dạng. Bạn đọc được bằng chính mắt mình (curl -i) — chính vì thế HTTP dễ học.

Toàn cảnh

Client vs server — hai vai trò duy nhất

Mọi ứng dụng web bạn sẽ ship đều là hai vai trò này nói chuyện. Khóa học này giúp bạn trở thành người xây đúng phía cần xây.

Client — bên hỏi

Trình duyệt, app điện thoại, hay curl của bạn. Nó mở đầu mọi cuộc hội thoại, hiển thị kết quả, và không giữ gì giữa các lần truy cập.

Client theo thiết kế là 'không kiên nhẫn': hỏi một lần, chờ, rồi tiếp tục.

Server — bên trả lời

Một chương trình trên máy, chờ ở một cổng. Nó làm việc thật: đọc cơ sở dữ liệu, chạy logic, dựng câu trả lời.

Server theo thiết kế là 'kiên nhẫn': chờ mãi, trả lời hàng nghìn lần mỗi giây.

Toàn cảnh

Điều xảy ra khi bạn click một link

Bốn nhịp, nửa giây. Mọi thứ trong khóa học này đều là phóng to một trong những nhịp này.

  1. 1

    Bạn click

    Trình duyệt quyết định 'tôi cần địa chỉ đó' và dựng một request: URL, method (GET), headers — một tin nhắn text nhỏ.

  2. 2

    Nó đi qua mạng

    Request đi qua mạng đến đúng máy, đúng cổng. (TLS mã hóa chuyến đi — chủ đề sau này.)

  3. 3

    Server làm việc

    Server chuyển request sang ứng dụng của bạn. Ứng dụng làm việc: đọc dữ liệu, chạy logic, dựng trang hay JSON.

  4. 4

    Bạn thấy pixel

    Response đi về. Trình duyệt phân tích HTML, áp dụng CSS, chạy JS, và vẽ. Xong — cho đến cú click tiếp theo.

01
Phần 1

HTTP — ngôn ngữ của web

Bộ quy tắc cho việc client hỏi và server trả lời: giải phẫu request và response, methods, status codes, headers, redirect.

HTTP · request

Một request gồm bốn phần

Tất cả những gì client có thể nói, gói trong một tin nhắn. Không hơn, không kém.

URL — ở đâu

Địa chỉ được gọi: host (server nào) + path (điều gì trên đó) + query tùy chọn (?sort=new). Là dòng 'gửi ai' của tin nhắn.

Method — làm gì

Động từ: GET, POST, PUT, PATCH, DELETE. Tuyên bố ý định để server biết phải làm gì trước khi đọc bất cứ thứ gì khác.

Headers — ai và ra sao

Các dòng metadata, mỗi dòng một dữ kiện: ai đang hỏi (User-Agent), body ở định dạng gì (Content-Type), bạn khai là ai (Authorization).

Body — dữ liệu gửi kèm

Nội dung thật đang gửi: form, JSON, file. Tùy chọn — GET không có; POST và PUT thường mang theo.

HTTP · trên 'dây'

Một trao đổi thật, không cần trình duyệt

Đây chính là thứ di chuyển giữa client và server. Trái: request (method + URL + headers + body). Phải: response (status + headers + body).

request.txt
GET /users/42?sort=new HTTP/1.1
Host: api.shop.com
Content-Type: application/json

{"name": "Ada"}

tin nhắn của client — method, URL, ai đang hỏi, và dữ liệu gửi kèm

response.txt
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 46

{"id": 42, "name": "Ada", "posts": 3}

câu trả lời của server — chuyện gì xảy ra (200), định dạng gì, và dữ liệu

HTTP · URL

Giải phẫu một địa chỉ

Mỗi URL là năm công việc trong một dòng. Trình duyệt và server tách nó ra theo cùng một cách mỗi lần.

url.txt
https://api.shop.com:8443/users/42?sort=new&page=2

scheme   https          how to talk
host     api.shop.com   which machine answers
port     :8443          which door (80 and 443 are the defaults)
path     /users/42      which resource
query    ?sort=new...   options, as key=value pairs

Đa số thời gian cổng bị giấu — :80 cho http, :443 cho https được ngầm hiểu.

HTTP · response

Một response gồm ba phần

Ảnh phản chiếu của request — nhưng nó bắt đầu bằng một phán quyết: mã trạng thái.

Status line

Dòng đầu: HTTP/1.1 200 OK. Mã ba chữ số là tiêu đề — thành công, đổi hướng hay lỗi — trước cả một byte nội dung.

Headers

Metadata về nội dung: định dạng (Content-Type), kích thước (Content-Length), gợi ý cache. Mỗi dòng dạng 'Tên: giá trị', như headers của request.

Body

Nội dung thật: trang HTML, JSON, ảnh — hoặc không có gì. Mọi thứ sau dòng trống ngăn cách với headers.

HTTP · methods

Methods — các động từ của web

Method là lời cam kết về ý định. Bạn và server đều có thể dựa vào nó: GET không bao giờ thay đổi gì, POST tạo mới, DELETE xóa.

MethodNghĩa làVí dụ
GETĐọc — không bao giờ thay đổi gìGET /users/42
POSTTạo mới, hoặc gửi thứ gì đóPOST /users
PUTThay thế toàn bộ tài nguyênPUT /users/42
PATCHChỉnh một phần tài nguyênPATCH /users/42
DELETEXóa một tài nguyênDELETE /users/42
HTTP · methods

Chọn đúng động từ

Chọn theo ý định, không theo thói quen. Method nói cho cache, trình duyệt và app khác biết endpoint của bạn an toàn để đụng đến ra sao.

GET là một lời hứa

GET nghĩa là 'cho tôi xem', không bao giờ 'thay đổi gì'. Trình duyệt, cache và công cụ tìm kiếm dựa vào nó — nên GET phải an toàn để lặp lại.

POST chuyên mang theo dữ liệu

POST để gửi: form, bản ghi mới, tải file lên. Có body, và lặp lại có thể tạo bản ghi trùng — điều đó được chấp nhận.

PUT vs PATCH

PUT thay thế toàn bộ tài nguyên; PATCH chỉnh một phần. Thực tế: đa số app chỉ dùng POST cho 'ghi' và giữ sự đơn giản.

DELETE xóa

DELETE xóa một tài nguyên. Response là mã trạng thái (200 hay 204), không phải trang — client kiểm tra mã, không phải pixel.

HTTP · mã trạng thái

Status code — câu trả lời một dòng của server

Mọi response bắt đầu bằng một số ba chữ số. Chữ số đầu kể trọn câu chuyện trong một cái nhìn.

2xxNghĩa làMã chính
2xxThành công — xong việc200 OK · 201 Created
3xxĐổi hướng — sang nơi khác mà xem301 moved · 302 see other
4xxLỗi phía client — lỗi của bạn (nói nhẹ nhàng)400 bad · 401 not authed · 403 denied · 404 not found
5xxLỗi phía server — lỗi do phía máy chủ500 internal error
HTTP · mã trạng thái

Chín mã bạn sẽ thực sự gặp

Ghi nhớ khuôn mẫu, không phải danh sách: 2xx xong, 3xx đi nơi khác, 4xx lỗi của bạn, 5xx lỗi của chúng tôi.

CodeNghĩa làBạn làm gì
200 OKMọi thứ ổn; đây là dữ liệuKhông có gì — xong việc
201 CreatedMột tài nguyên mới ra đời (POST của bạn thành công)Giữ lại header Location — địa chỉ của thứ mới
301 Moved PermanentlyĐịa chỉ này đã đổi vĩnh viễnTrình duyệt tự cập nhật đường dẫn; bạn nên sửa link cũ
302 FoundSang URL kia mà xem — chỉ lần nàyTrình duyệt tự theo; bạn hầu như không bao giờ thấy nó
400 Bad RequestRequest của bạn sai cấu trúc — tôi không parse nổiKiểm tra URL, body, headers của bạn
401 UnauthorizedBạn là ai? Tôi cần thông tin xác thựcĐăng nhập / thêm header Authorization
403 ForbiddenTôi biết bạn là ai — nhưng khôngVấn đề quyền; hỏi quản trị viên
404 Not FoundKhông có thứ gì ở địa chỉ đóKiểm tra URL — gõ sai, hoặc đã bị xóa
500 Internal ErrorPhía tôi sập — không phải lỗi của bạnXem log server; trang lỗi thường chỉ đúng dòng code
HTTP · cặp hay nhầm nhất

401 vs 403 — danh tính, rồi quyền

Cặp hay nhầm nhất trong HTTP. 401 là vấn đề danh tính; 403 là vấn đề quyền.

401 — bạn là ai?

Bạn chưa trình thông tin xác thực, hoặc thông tin sai. Server đang yêu cầu bạn tự nhận diện.

Cách sửa: đăng nhập, thêm token. Sau đó, cánh cửa có thể mở.

403 — tôi biết bạn, nhưng không

Thông tin xác thực đúng — nhưng tài khoản đó không có quyền với tài nguyên này.

Cách sửa: không ai code sai; đó là vấn đề quyền.

HTTP · headers

Bốn headers trả lời những câu hỏi thường gặp

Có tổng cộng ~100 headers. Bốn cái này trả lời những câu hỏi xuất hiện nhiều nhất.

Host

Server nào mà bạn đang gọi — bắt buộc, vì virtual host đặt nhiều site trên một IP.

Content-Type

Định dạng của body: text/html, application/json… Dấu hiệu đầu tiên của server về cách đọc body của bạn.

User-Agent

Danh thiếp: trình duyệt, app hay curl nào đang hỏi. Dùng cho phân tích và tương thích.

Authorization

Thông tin xác thực của bạn, thường là Bearer token. Đây là cách API cho bạn vào mà không cần trang đăng nhập.

HTTP · redirect

Vũ khúc redirect

Redirect không phải lỗi — nó là tấm biển chỉ đường. Bạn không viết nó, bạn chỉ xem nó diễn ra.

  1. 1

    Bạn gọi địa chỉ cũ

    GET /old-page. Server biết nó đã dời — nhưng không gửi trang, nó gửi một tấm biển chỉ đường.

  2. 2

    Server chỉ đường

    301 + header Location: /new-page. Một response nhỏ xíu, không nội dung — chỉ là 'sang đó mà'.

  3. 3

    Trình duyệt tự tuân theo

    Nó gọi lại URL mới, nhận 200, và hiển thị trang. Từ chỗ ngồi của bạn, nó chỉ như một cú click.

HTTP · việc của server

Web server thực sự làm gì

Bỏ qua phần quảng cáo: một web server là chương trình lặp lại bốn bước, hàng nghìn lần mỗi giây.

  1. 1

    Lắng nghe trên một cổng

    Nó chờ trên một cổng (80 cho HTTP, 443 cho HTTPS) các kết nối đến — như để điện thoại luôn sẵn sàng nghe gọi.

  2. 2

    Phân tích request

    Nó giải mã các byte thành method, URL, headers, body — bốn phần đã nói ở trên.

  3. 3

    Chạy code của bạn

    Nó chuyển request sang ứng dụng của bạn (Flask trong khóa này), nơi quyết định làm gì — thường là: đọc dữ liệu, dựng trang.

  4. 4

    Gửi response

    Nó gói kết quả thành status + headers + body và gửi lại. Rồi quay về bước 1.

HTTP · cổng

Cổng là một số cửa

Một máy chạy nhiều dịch vụ; cổng chọn cánh cửa. Production trả lời ở 80/443; dev server của Flask thường mở 5000.

ops@vps — zsh
$ ss -ltn | grep -E ':(80|443|5000) '
LISTEN 0 511 *:80 *:*
LISTEN 0 511 *:443 *:*
LISTEN 0 128 127.0.0.1:5000 0.0.0.0:*
$ curl -i http://127.0.0.1:5000/ | head -1
HTTP/1.1 200 OK
80 and 443 open to the world; 5000 only to this machine (127.0.0.1)
02
Phần 2

Flask — ứng dụng web Python của bạn

Web server nói bằng byte; bạn nghĩ bằng Python. Flask là lớp mỏng ở giữa — một route là lời hứa: 'khi URL + method này đến, chạy hàm này'.

Flask · nó là gì

Flask trong bốn câu

Framework là bộ khung bạn không phải tự xây. Flask là bộ khung nhẹ nhất trong các framework Python web phổ biến.

Một micro-framework

Cố tình nhỏ: routing, parse request, response. Cơ sở dữ liệu, admin, xác thực — bạn gắn thêm chỉ những gì cần.

Python vào, HTTP ra

Bạn viết hàm Python thuần; Flask lo phần lộn xộn — byte, headers, mạng. Lớp mỏng, không phải nền tảng.

Route = lời hứa

Mỗi @app.route đăng ký một lời hứa: 'khi method này chạm URL này, chạy hàm này'. Phần còn lại là thủ tục sổ sách.

Dev server miễn phí

flask run cho bạn một server chạy được để phát triển. Nó không đạt chuẩn production — đó là việc của nginx (chủ đề sau).

Flask · ứng dụng đầu tiên

Cả một website, 8 dòng

Đây là một ứng dụng web hoàn chỉnh, chạy được. Hai route: một cho người (HTML), một cho máy (JSON).

app.py
from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/")
def home():
    return "<h1>Hello, shipper!</h1>"

@app.route("/api/hello")
def api_hello():
    return jsonify(name="shipper", status="alive")

Chạy flask run, mở http://127.0.0.1:5000 — đó là toàn bộ phía server của một ứng dụng web.

Flask · chạy ứng dụng

Hai terminal, zero trình duyệt

Đó là toàn bộ vòng lặp: Python trên máy bạn trả lời HTTP trên một cổng. Bạn test được trước khi người nào thấy nó.

ops@vps — zsh
$ flask run
* Running on http://127.0.0.1:5000
$ curl -i http://127.0.0.1:5000/
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
<h1>Hello, shipper!</h1>
$ curl http://127.0.0.1:5000/api/hello
{"name":"shipper","status":"alive"}
Flask · route cận cảnh

Route cận cảnh

Khi đã biết lời hứa, route chỉ là biểu mẫu đăng ký. Bốn chi tiết đáng biết.

Decorator là bước đăng ký

@app.route("/about") đăng ký hàm bên dưới cho GET /about. Tên hàm có thể là gì cũng được — Flask không quan tâm.

Method là đăng ký thêm

Route mặc định là GET (và HEAD). Endpoint ghi phải khai: @app.route("/users", methods=["POST"]). Method sai → 405.

Giá trị trả về là response

Trả về chuỗi → trang HTML. Trả về jsonify(...) → JSON. Trả về (body, 404) → bạn tự kiểm soát mã trạng thái.

URL có thể mang giá trị

/users/<int:uid> gắn 42 trong /users/42 với tham số uid — có kiểu, ngay trong địa chỉ.

Flask · response

Ba cách trả lời

Cùng app, ba kiểu trả về. Giá trị trả về quyết định client nhận gì — và ở mã trạng thái nào.

responses.py
from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/")
def page():
    return "<h1>Hello, shipper!</h1>"   # -> text/html

@app.route("/api/hello")
def api():
    return jsonify(name="shipper")      # -> application/json

@app.route("/missing")
def gone():
    return "not here", 404               # -> you pick the status

Một quy tắc cần nhớ: hàm trả về gì, Flask tự gói thành status + headers + body.

Flask · hai đối tượng

HTML cho mắt, JSON cho máy

Một app thường làm cả hai: route HTML cho người, route /api cho máy.

HTML — cho mắt

Trình duyệt phân tích, trang trí, vẽ nó. Con người là người tiêu dùng cuối; trang là sản phẩm.

Test bằng một cú click trình duyệt. Pixel đúng là chạy.

JSON — cho máy

Máy đọc nó: app khác, điện thoại, framework frontend. Key và giá trị, không trang trí.

Test bằng curl -i. Mã 200 và JSON parse được là chạy.

Flask · đọc input

Bốn cánh cửa client có thể gõ

Client gửi dữ liệu theo nhiều hình dạng; Flask mở mỗi hình dạng ở một chỗ riêng. Biết nhìn đúng chỗ, cú pháp tự theo sau.

input.py
from flask import request

@app.route("/users/<int:uid>")       # 1. URL parameter
def show_user(uid):
    return jsonify(uid=uid)

@app.route("/search")
def search():
    q    = request.args.get("q")    # 2. query string: /search?q=shoes
    name = request.form.get("name") # 3. form field (login, checkout...)
    body = request.json              # 4. JSON body (from an API client)

Một ứng dụng, bốn lối vào. <uid> đến từ URL; phần còn lại nằm trên đối tượng request.

Flask · kênh input

Mỗi loại dữ liệu đáp xuống đâu

Ghép kênh với việc — đó là toàn bộ quyết định thiết kế phía sau mọi API.

KênhĐáp trong FlaskVí dụDùng cho
Tham số URL<int:uid> in the route/users/42Tài nguyên nào — một phần của địa chỉ
Query stringrequest.args/search?q=shoesBộ lọc, tùy chọn, phân trang
Form bodyrequest.form<form> postsĐăng nhập, thanh toán — form trình duyệt kinh điển
JSON bodyrequest.jsoncurl -d '{...}'API nói chuyện với API — mặc định thời nay
Flask · query string

Đọc query string, an toàn

Giá trị query đến dưới dạng chuỗi — kể cả '42'. Đặt giá trị mặc định, và tự chuyển kiểu.

query.py
@app.route("/search")
def search():
    q = request.args.get("q", "")              # ?q=shoes -> "shoes", else ""
    page = request.args.get("page", 1, type=int)  # ?page=2 -> 2 (an int)
    if not q:
        return "nothing to search", 400
    return jsonify(q=q, page=page)

get(key, default, type=...) là giải pháp 90% cho query string.

Flask · cơ chế

Bên trong một request của Flask

Bốn trạm giữa 'byte đến' và 'byte đi'. Hiểu route giúp gỡ lỗi nhanh gấp 10 lần.

  1. 1

    Server nhận

    Web server (hay dev server của Flask) nhận byte HTTP thô và chuyển cho Flask.

  2. 2

    Flask khớp route

    Nó đi qua các lời hứa đã đăng ký: method + URL. Không khớp? 404 ngay lập tức — code của bạn không chạy.

  3. 3

    Hàm của bạn chạy

    Hàm view đọc input (args, form, json), làm việc — thường là: lấy dữ liệu — rồi trả về một giá trị.

  4. 4

    Flask gói và gửi

    Giá trị trả về thành status + headers + body, và đi về phía client. Vòng đi-về khép lại.

Flask · gỡ lỗi

Lỗi chỉ là mã trạng thái

Dev server của Flask hiển thị traceback đầy đủ khi 500 — dòng cuối thường chỉ đúng lỗi. Sửa, lưu, curl lại.

ops@vps — zsh
$ curl -i http://127.0.0.1:5000/typo
HTTP/1.1 404 NOT FOUND
not found
$ curl -i http://127.0.0.1:5000/broken
HTTP/1.1 500 INTERNAL SERVER ERROR
Traceback (most recent call last):
File "app.py", line 12, in order_total
NameError: name 'price' is not defined
read the LAST line of a traceback - it names the bug
Flask · lỗi

Trả về lỗi có chủ đích

Một app đúng chuẩn sẽ lỗi lịch sự: mã đúng nói cho client biết chính xác nên thử gì tiếp.

Bạn tự chọn mã

return 'not found', 404 — giá trị thứ hai đặt mã trạng thái. Đừng trả 200 cho mọi thứ.

400 vs 404

400: bản thân request sai cấu trúc. 404: request đúng, nhưng thứ đó không tồn tại.

API đọc mã, không đọc trang

Client API rẽ nhánh theo mã trạng thái. 4xx và 5xx của bạn là chỉ dẫn, không phải trang trí.

03
Phần 3

curl — trình duyệt của lập trình viên

API trả JSON thì trình duyệt không nhìn thấy gì. curl là client HTTP của terminal: thực thi một request và in ra response thô.

curl · vì sao nó tồn tại

Vì sao lập trình viên sống trong curl

curl là người anh em thô mộc và trung thực của trình duyệt: nó cho thấy phần ống dẫn mà trình duyệt giấu.

Trình duyệt giấu phần ống dẫn

Trình duyệt cho bạn xem kết quả đã vẽ và nuốt chửng mã trạng thái, headers, redirect. curl cho thấy mọi byte.

API không dành cho trình duyệt

Mở endpoint JSON bằng trình duyệt là đường cụt. curl là môi trường sống tự nhiên của API.

Bạn kiểm soát request

Tự chọn method, headers, body, đúng URL. Những gì trình duyệt làm thay bạn khi click, bạn làm có chủ đích.

Nó chạy được trong script

curl sống trong vòng lặp shell, Makefile và pipeline CI. Nếu một test gõ được, nó tự động hóa được.

curl · thực hành

Một app, bốn câu trả lời

Thành công, dữ liệu, dữ liệu lọc, thất bại. Đây là cảm giác test một API.

ops@vps — zsh
$ curl -i http://127.0.0.1:5000/
HTTP/1.1 200 OK
<h1>Hello, shipper!</h1>
$ curl http://127.0.0.1:5000/api/hello
{"name":"shipper","status":"alive"}
$ curl http://127.0.0.1:5000/search?q=shoes
{"q":"shoes","page":1}
$ curl -i http://127.0.0.1:5000/nope
HTTP/1.1 404 NOT FOUND
not found
curl · bộ công cụ

Sáu cờ, đủ 95% việc test API

Mặc định của curl là: GET một URL và in body. Các cờ biến nó thành client API đầy đủ.

FlagNó làm gìVí dụ
-X POSTĐổi methodcurl -X POST http://…/users
-H 'K: V'Thêm header-H 'Content-Type: application/json'
-d dataĐính kèm body-d '{"name":"Ada"}'
-iHiển thị status line + headerscurl -i http://…/
-vVerbose: toàn bộ câu chuyện kết nốicurl -v http://…/
-o fileLưu body vào file thay vì in màn hìnhcurl -o page.html http://…/
curl · câu lệnh kinh điển

Tạo một bản ghi từ terminal

Method + header + body + URL. Một khuôn mẫu này đáp ứng phần lớn việc 'gửi dữ liệu vào API của bạn'.

post.sh
# the classic "create a record" one-liner
curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"name": "Ada"}' \
  http://127.0.0.1:5000/users

# ...and check what the server actually said
curl -i -X POST \
  -H 'Content-Type: application/json' \
  -d '{"name": "Ada"}' \
  http://127.0.0.1:5000/users

Với -i bạn nên thấy HTTP/1.1 201 CREATED — bằng chứng bản ghi đã ra đời.

curl · bên trong

-v: xem cuộc hội thoại diễn ra

Dòng bắt đầu bằng > là của bạn; dòng bắt đầu bằng < là của server. Đây là toàn bộ giao thức, ngay trước mắt bạn.

ops@vps — zsh
$ curl -v http://127.0.0.1:5000/ 2>&1 | head -12
* Trying 127.0.0.1:5000...
* Connected to 127.0.0.1 port 5000
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/8.5.0
> Accept: */*
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
<h1>Hello, shipper!</h1>
you typed one command; curl did the whole dance above
Toàn cảnh

Toàn bộ stack trong một bức tranh

Ba vai trò, một đường ống — và chủ đề tiếp theo (nginx) cắm vào đúng chỗ này.

🌐 Clients

Trình duyệt cho người, curl cho bạn. Chúng mở đầu mọi cuộc hội thoại.

request ▶ ◀ response

🚪 nginx — cánh cửa trước

Chủ đề sau. Xử lý HTTPS, serve file tĩnh, chuyển request thật đi tiếp.

request ▶ ◀ response

🐍 Flask app

Code của bạn: route, dữ liệu, quyết định. Dựng response và gửi ngược lại.

client nói chuyện với cánh cửa · cánh cửa nói chuyện với ứng dụng · ứng dụng nói chuyện với thế giới — tất cả bằng HTTP thuần

Request. Response. Lặp lại.

Mọi ứng dụng web bạn sẽ ship đều là một vòng lặp: lắng nghe, phân tích, chạy, trả lời. Flask viết câu trả lời; curl chứng minh chúng đến nơi.