I/O
HTTP Server
http.createServer của Node.js so với ServeMux (Go 1.22+), axum (Rust), Network.framework (Swift) và HttpServer (Java) để viết HTTP server có route.
- Phiên bản tối thiểu
- Node.js ≥ 18Go ≥ 1.22Rust ≥ 1.85Swift ≥ 5.7Java ≥ 25
- Đã chạy thử trên
- Node.js 24.12.0Go 1.27.1Rust 1.98.1Swift 6.2.4Java 25.0.4.1
Code Node.js là ES module: lưu file .mjs hoặc đặt "type": "module" trong package.json.
Node.js và Go có HTTP server ngay trong standard library, không cần framework để bắt đầu. Rust std thì không — cần một crate như axum (routing + path param gọn như ServeMux của Go). Swift cũng vậy: Foundation không có HTTP server, ví dụ dưới đây tự parse dòng request đầu tiên qua Network.framework — đủ cho demo, không phải một HTTP server đúng chuẩn. Java có com.sun.net.httpserver.HttpServer (module jdk.httpserver) từ lâu, khớp path theo tiền tố thay vì pattern có wildcard.
Server có route
import http from 'node:http'
function handler(request, response) {
response.writeHead(200, { 'Content-type':'text/plain' })
response.write('hello world')
response.end()
}
const server = http.createServer(handler)
server.listen(8080)package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
})
http.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello %s", r.PathValue("name"))
})
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}// Cargo.toml: axum = "0.8"
// Cargo.toml: tokio = { version = "1", features = ["full"] }
use axum::extract::Path;
use axum::routing::get;
use axum::Router;
async fn hello(Path(name): Path<String>) -> String {
format!("hello {name}")
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(|| async { "hello world" }))
.route("/hello/{name}", get(hello));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
axum::serve(listener, app).await.unwrap();
}import Network
let listener = try NWListener(using: .tcp, on: 8080)
listener.newConnectionHandler = { connection in
connection.start(queue: .main)
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { data, _, _, _ in
guard let data, let request = String(data: data, encoding: .utf8) else { return }
let path = request.split(separator: " ")[1] // "GET /hello/neko HTTP/1.1" -> "/hello/neko"
let status: String
let body: String
if path == "/" {
status = "200 OK"
body = "hello world"
} else if path.hasPrefix("/hello/") {
status = "200 OK"
body = "hello \(path.dropFirst("/hello/".count))"
} else {
status = "404 Not Found"
body = "not found"
}
let response = "HTTP/1.1 \(status)\r\nContent-Length: \(body.utf8.count)\r\n\r\n\(body)"
connection.send(content: response.data(using: .utf8), completion: .contentProcessed { _ in connection.cancel() })
}
}
listener.start(queue: .main)
dispatchMain()import com.sun.net.httpserver.HttpServer;
import java.net.InetSocketAddress;
void main() throws Exception {
var server = HttpServer.create(new InetSocketAddress(8080), 0);
server.createContext("/", exchange -> {
byte[] body = "hello world".getBytes();
exchange.sendResponseHeaders(200, body.length);
exchange.getResponseBody().write(body);
exchange.close();
});
server.createContext("/hello/", exchange -> { // khớp theo tiền tố, không có {name} như ServeMux
String name = exchange.getRequestURI().getPath().substring("/hello/".length());
byte[] body = ("hello " + name).getBytes();
exchange.sendResponseHeaders(200, body.length);
exchange.getResponseBody().write(body);
exchange.close();
});
server.start();
}$ curl http://localhost:8080
hello worldClient (http_client.js, chạy trong khi một server ở trên đang bật): fetch() toàn cục thay cho http.get()/http.request() cho các request đơn giản.
const response = await fetch('http://localhost:8080')
console.log(await response.text())package main
import (
"fmt"
"io"
"net/http"
)
func main() {
res, err := http.Get("http://localhost:8080")
if err != nil {
panic(err)
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
}// Cargo.toml: reqwest = "0.13"
// Cargo.toml: tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() {
let body = reqwest::get("http://localhost:8080").await.unwrap().text().await.unwrap();
println!("{body}");
}import Foundation
let (data, _) = try await URLSession.shared.data(from: URL(string: "http://localhost:8080")!)
print(String(data: data, encoding: .utf8)!)import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
void main() throws Exception {
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("http://localhost:8080")).build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
IO.println(response.body());
}$ node http_client.js
hello world# chỉ áp dụng cho các server có route /hello/{name} (Go, Rust, Swift, Java) — JS server ở trên không có route này
$ curl http://localhost:8080/hello/gopher
hello gopherTham khảo: github.com/miguelmota/golang-for-nodejs-developers#http-server