HTTP RESTful服务 #
一、RESTful API概述 #
1.1 REST原则 #
text
┌─────────────────────────────────────────────────────────┐
│ REST架构原则 │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. 统一接口 (Uniform Interface) │
│ ├── 资源标识 (URI) │
│ ├── 资源操作 (HTTP方法) │
│ ├── 自描述消息 │
│ └── 超媒体驱动 │
│ │
│ 2. 无状态 (Stateless) │
│ 每个请求包含所有必要信息 │
│ │
│ 3. 可缓存 (Cacheable) │
│ 响应可被缓存 │
│ │
│ 4. 分层系统 (Layered System) │
│ 客户端无需知道连接的是终端还是中间层 │
│ │
└─────────────────────────────────────────────────────────┘
1.2 HTTP方法映射 #
| HTTP方法 | CRUD操作 | 说明 |
|---|---|---|
| GET | Read | 获取资源 |
| POST | Create | 创建资源 |
| PUT | Update | 更新资源 |
| DELETE | Delete | 删除资源 |
| PATCH | Partial Update | 部分更新 |
1.3 HTTP状态码 #
| 状态码 | 类别 | 说明 |
|---|---|---|
| 2xx | 成功 | 请求成功 |
| 3xx | 重定向 | 需要进一步操作 |
| 4xx | 客户端错误 | 请求有误 |
| 5xx | 服务器错误 | 服务器处理失败 |
二、轻量级HTTP服务器 #
2.1 使用JDK内置HttpServer #
java
package com.example.network.http;
import com.sun.net.httpserver.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.BiFunction;
public class LightweightHttpServer {
private HttpServer server;
private final int port;
private final Map<String, RouteHandler> routes = new HashMap<>();
@FunctionalInterface
public interface RouteHandler {
Response handle(Request request);
}
public static class Request {
public final String method;
public final String path;
public final Map<String, String> query;
public final Map<String, String> headers;
public final String body;
public Request(String method, String path, Map<String, String> query,
Map<String, String> headers, String body) {
this.method = method;
this.path = path;
this.query = query;
this.headers = headers;
this.body = body;
}
}
public static class Response {
public final int statusCode;
public final String body;
public final Map<String, String> headers;
public Response(int statusCode, String body) {
this(statusCode, body, new HashMap<>());
}
public Response(int statusCode, String body, Map<String, String> headers) {
this.statusCode = statusCode;
this.body = body;
this.headers = headers;
}
public static Response ok(String body) {
return new Response(200, body);
}
public static Response created(String body) {
return new Response(201, body);
}
public static Response badRequest(String message) {
return new Response(400, "{\"error\":\"" + message + "\"}");
}
public static Response notFound(String message) {
return new Response(404, "{\"error\":\"" + message + "\"}");
}
public static Response serverError(String message) {
return new Response(500, "{\"error\":\"" + message + "\"}");
}
}
public LightweightHttpServer(int port) {
this.port = port;
}
public void get(String path, RouteHandler handler) {
routes.put("GET:" + path, handler);
}
public void post(String path, RouteHandler handler) {
routes.put("POST:" + path, handler);
}
public void put(String path, RouteHandler handler) {
routes.put("PUT:" + path, handler);
}
public void delete(String path, RouteHandler handler) {
routes.put("DELETE:" + path, handler);
}
public void start() throws IOException {
server = HttpServer.create(new InetSocketAddress(port), 0);
server.setExecutor(Executors.newFixedThreadPool(4));
server.createContext("/", this::handleRequest);
server.start();
System.out.println("HTTP服务器启动,端口: " + port);
}
public void stop() {
if (server != null) {
server.stop(0);
}
}
private void handleRequest(HttpExchange exchange) throws IOException {
try {
String method = exchange.getRequestMethod();
String path = exchange.getRequestURI().getPath();
Map<String, String> query = parseQuery(exchange.getRequestURI().getQuery());
Map<String, String> headers = new HashMap<>();
for (Map.Entry<String, List<String>> entry : exchange.getRequestHeaders().entrySet()) {
if (!entry.getValue().isEmpty()) {
headers.put(entry.getKey(), entry.getValue().get(0));
}
}
String body = "";
if (exchange.getRequestBody() != null) {
body = new String(exchange.getRequestBody().readAllBytes());
}
Request request = new Request(method, path, query, headers, body);
RouteHandler handler = routes.get(method + ":" + path);
Response response;
if (handler != null) {
response = handler.handle(request);
} else {
response = Response.notFound("Resource not found: " + path);
}
sendResponse(exchange, response);
} catch (Exception e) {
e.printStackTrace();
sendResponse(exchange, Response.serverError(e.getMessage()));
}
}
private void sendResponse(HttpExchange exchange, Response response) throws IOException {
exchange.getResponseHeaders().set("Content-Type", "application/json");
response.headers.forEach((k, v) -> exchange.getResponseHeaders().set(k, v));
byte[] bytes = response.body.getBytes();
exchange.sendResponseHeaders(response.statusCode, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
}
private Map<String, String> parseQuery(String query) {
Map<String, String> params = new HashMap<>();
if (query != null && !query.isEmpty()) {
for (String param : query.split("&")) {
String[] pair = param.split("=");
if (pair.length == 2) {
params.put(pair[0], URLDecoder.decode(pair[1], "UTF-8"));
}
}
}
return params;
}
public static void main(String[] args) throws IOException {
LightweightHttpServer server = new LightweightHttpServer(8080);
server.get("/api/status", req -> Response.ok(
"{\"status\":\"running\",\"uptime\":" +
System.currentTimeMillis() + "}"));
server.get("/api/sensors", req -> Response.ok(
"[{\"name\":\"temperature\",\"value\":25.5}," +
"{\"name\":\"humidity\",\"value\":60.0}]"));
server.get("/api/sensors/:name", req -> {
String name = req.path.split("/")[3];
return Response.ok("{\"name\":\"" + name + "\",\"value\":" +
(20 + Math.random() * 10) + "}");
});
server.post("/api/led", req -> {
String body = req.body;
return Response.created("{\"message\":\"LED controlled\"}");
});
server.start();
Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
}
}
2.2 RESTful设备API #
java
package com.example.network.http;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class DeviceAPI {
private final Map<String, Device> devices = new ConcurrentHashMap<>();
private final LightweightHttpServer server;
public static class Device {
public String id;
public String name;
public String status;
public Map<String, Object> sensors = new HashMap<>();
public long lastUpdate;
public Device(String id, String name) {
this.id = id;
this.name = name;
this.status = "online";
this.lastUpdate = System.currentTimeMillis();
}
public void addSensor(String name, Object value) {
sensors.put(name, value);
}
}
public DeviceAPI(int port) {
this.server = new LightweightHttpServer(port);
setupRoutes();
}
private void setupRoutes() {
server.get("/api/devices", req -> {
StringBuilder sb = new StringBuilder("[");
boolean first = true;
for (Device device : devices.values()) {
if (!first) sb.append(",");
sb.append(toJson(device));
first = false;
}
sb.append("]");
return LightweightHttpServer.Response.ok(sb.toString());
});
server.get("/api/devices/:id", req -> {
String id = extractId(req.path);
Device device = devices.get(id);
if (device != null) {
return LightweightHttpServer.Response.ok(toJson(device));
}
return LightweightHttpServer.Response.notFound("Device not found");
});
server.post("/api/devices", req -> {
String id = UUID.randomUUID().toString();
Device device = new Device(id, "Device-" + id.substring(0, 8));
devices.put(id, device);
return LightweightHttpServer.Response.created(toJson(device));
});
server.put("/api/devices/:id", req -> {
String id = extractId(req.path);
Device device = devices.get(id);
if (device != null) {
device.lastUpdate = System.currentTimeMillis();
return LightweightHttpServer.Response.ok(toJson(device));
}
return LightweightHttpServer.Response.notFound("Device not found");
});
server.delete("/api/devices/:id", req -> {
String id = extractId(req.path);
Device removed = devices.remove(id);
if (removed != null) {
return LightweightHttpServer.Response.ok(
"{\"message\":\"Device deleted\"}");
}
return LightweightHttpServer.Response.notFound("Device not found");
});
server.get("/api/devices/:id/sensors", req -> {
String id = extractId(req.path);
Device device = devices.get(id);
if (device != null) {
return LightweightHttpServer.Response.ok(
sensorsToJson(device.sensors));
}
return LightweightHttpServer.Response.notFound("Device not found");
});
}
private String extractId(String path) {
String[] parts = path.split("/");
return parts.length >= 4 ? parts[3] : null;
}
private String toJson(Device device) {
return String.format(
"{\"id\":\"%s\",\"name\":\"%s\",\"status\":\"%s\"," +
"\"lastUpdate\":%d,\"sensors\":%s}",
device.id, device.name, device.status,
device.lastUpdate, sensorsToJson(device.sensors));
}
private String sensorsToJson(Map<String, Object> sensors) {
StringBuilder sb = new StringBuilder("{");
boolean first = true;
for (Map.Entry<String, Object> entry : sensors.entrySet()) {
if (!first) sb.append(",");
sb.append("\"").append(entry.getKey()).append("\":");
if (entry.getValue() instanceof String) {
sb.append("\"").append(entry.getValue()).append("\"");
} else {
sb.append(entry.getValue());
}
first = false;
}
sb.append("}");
return sb.toString();
}
public void start() throws IOException {
server.start();
}
public void stop() {
server.stop();
}
public void addDevice(Device device) {
devices.put(device.id, device);
}
public Device getDevice(String id) {
return devices.get(id);
}
public static void main(String[] args) throws IOException {
DeviceAPI api = new DeviceAPI(8080);
Device device1 = new Device("device-001", "Temperature Sensor");
device1.addSensor("temperature", 25.5);
device1.addSensor("humidity", 60.0);
api.addDevice(device1);
Device device2 = new Device("device-002", "Light Sensor");
device2.addSensor("light", 500);
api.addDevice(device2);
api.start();
System.out.println("设备API已启动");
System.out.println("GET http://localhost:8080/api/devices");
System.out.println("GET http://localhost:8080/api/devices/device-001");
Runtime.getRuntime().addShutdownHook(new Thread(api::stop));
}
}
三、JSON处理 #
3.1 简单JSON工具 #
java
package com.example.network.http;
import java.util.*;
public class JsonBuilder {
private final Map<String, Object> data = new LinkedHashMap<>();
public JsonBuilder put(String key, String value) {
data.put(key, value);
return this;
}
public JsonBuilder put(String key, Number value) {
data.put(key, value);
return this;
}
public JsonBuilder put(String key, Boolean value) {
data.put(key, value);
return this;
}
public JsonBuilder put(String key, Object value) {
data.put(key, value);
return this;
}
public JsonBuilder put(String key, Map<String, Object> value) {
data.put(key, value);
return this;
}
public JsonBuilder put(String key, List<?> value) {
data.put(key, value);
return this;
}
@Override
public String toString() {
return build();
}
public String build() {
StringBuilder sb = new StringBuilder("{");
boolean first = true;
for (Map.Entry<String, Object> entry : data.entrySet()) {
if (!first) sb.append(",");
sb.append("\"").append(entry.getKey()).append("\":");
sb.append(valueToJson(entry.getValue()));
first = false;
}
sb.append("}");
return sb.toString();
}
private String valueToJson(Object value) {
if (value == null) {
return "null";
} else if (value instanceof String) {
return "\"" + escapeString((String) value) + "\"";
} else if (value instanceof Number || value instanceof Boolean) {
return value.toString();
} else if (value instanceof Map) {
return mapToJson((Map<?, ?>) value);
} else if (value instanceof List) {
return listToJson((List<?>) value);
} else {
return "\"" + escapeString(value.toString()) + "\"";
}
}
private String mapToJson(Map<?, ?> map) {
StringBuilder sb = new StringBuilder("{");
boolean first = true;
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (!first) sb.append(",");
sb.append("\"").append(entry.getKey()).append("\":");
sb.append(valueToJson(entry.getValue()));
first = false;
}
sb.append("}");
return sb.toString();
}
private String listToJson(List<?> list) {
StringBuilder sb = new StringBuilder("[");
boolean first = true;
for (Object item : list) {
if (!first) sb.append(",");
sb.append(valueToJson(item));
first = false;
}
sb.append("]");
return sb.toString();
}
private String escapeString(String s) {
return s.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
public static JsonBuilder create() {
return new JsonBuilder();
}
public static String array(List<?> items) {
StringBuilder sb = new StringBuilder("[");
boolean first = true;
for (Object item : items) {
if (!first) sb.append(",");
if (item instanceof String) {
sb.append("\"").append(item).append("\"");
} else {
sb.append(item);
}
first = false;
}
sb.append("]");
return sb.toString();
}
}
四、总结 #
HTTP RESTful服务要点:
- REST原则:遵循REST架构风格设计API
- HTTP方法:正确使用GET/POST/PUT/DELETE
- 状态码:返回合适的HTTP状态码
- JSON格式:使用JSON作为数据交换格式
- 轻量级实现:适合嵌入式环境的HTTP服务器
下一章我们将学习框架与工具,提高开发效率。
最后更新:2026-03-27