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服务要点:

  1. REST原则:遵循REST架构风格设计API
  2. HTTP方法:正确使用GET/POST/PUT/DELETE
  3. 状态码:返回合适的HTTP状态码
  4. JSON格式:使用JSON作为数据交换格式
  5. 轻量级实现:适合嵌入式环境的HTTP服务器

下一章我们将学习框架与工具,提高开发效率。

最后更新:2026-03-27