JDK 内置的轻量级 HTTP 服务器 --- HttpServer

本文链接: http://blog.csdn.net/xietansheng/article/details/78704783

1. 概述

官方JavaDocsApi: com.sun.net.httpserver

HttpServer 是 JDK 1.6 以后内置的一个轻量级 HTTP 服务器(在 rt.jar 包中的 com.sun.net.httpserver 包下)。一个 HttpServer 实例被绑定到一个IP地址和端口号,并监听来自该地址的客户端TCP连接。其子类 HttpsServer 实现了 HTTPS 服务,还能处理 HTTPS 请求。

一个简单的 HTTP 服务器:

// 创建 http 服务器, 绑定本地 8080 端口
HttpServer httpServer = HttpServer.create(new InetSocketAddress(8080), 0);

// 创建上下文监听, "/" 表示匹配所有 URI 请求
httpServer.createContext("/", new HttpHandler() {
    @Override
    public void handle(HttpExchange httpExchange) throws IOException {
        /*
         * PS: 必须按顺序设置响应: 添加响应头, 发送响应码和内容长度, 写出响应内容, 关闭处理器
         */
        // 响应内容
        byte[] respContents = "Hello World".getBytes("UTF-8");

        // 设置响应头
        httpExchange.getResponseHeaders().add("Content-Type", "text/html; charset=UTF-8");
        // 设置响应code和内容长度
        httpExchange.sendResponseHeaders(200, respContents.length);

        // 设置响应内容
        httpExchange.getResponseBody().write(respContents);

        // 关闭处理器, 同时将关闭请求和响应的输入输出流(如果还没关闭)
        httpExchange.close();
    }
});

// 启动服务
httpServer.start();

浏览器访问: http://localhost:8080,输出: Hello World

使用 HttpServer 实现一个 HTTP 服务器主要涉及下面几个类:

  • HttpServer: 表示一个服务器实例
  • HttpContext: 服务器监听器的上下文
  • HttpHandler: 上下文对应的 http 请求处理器
  • HttpExchange: 对 http 请求和响应的数据封装

2. 服务器: HttpServer

创建 HttpServer 实例:

/**
 * 创建 HttpServer 实例, 参数说明:
 *     addr: 服务绑定的地址端口
 *     backlog: TCP连接最大并发数, 传 0 或负数表示使用默认值
 */
HttpServer httpServer = HttpServer.create​(InetSocketAddress addr, int backlog);

HttpServer 常用方法:

// 重新绑定地址和端口
void bind​(InetSocketAddress addr, int backlog)
// 获取当前绑定的地址
InetSocketAddress getAddress​()

/**
 * 创建监听的上下文, 请求 URI 根路径的匹配, 根据不同的 URI 根路径选择不同的 HttpHandler 处理请求,
 * 路径必须以 "/" 开头。路径 "/" 表示匹配所有的请求 URI(没有其他更具体的匹配路径除外)。
 */
HttpContext createContext​(String path)
HttpContext createContext​(String path, HttpHandler handler)

// 移除上下文监听
void removeContext​(HttpContext context)
void removeContext​(String path)

// 设置请求的线程执行器, 设置为 null 表示使用默认的执行器
void setExecutor​(Executor executor)
Executor getExecutor​()

// 启动服务
void start​()
// 最长等待指定时间后停止服务
void stop​(int delay)

3. 上下文: HttpContext

HTTP 上下文,实际上就是对请求的 URI 根路径匹配的监听,可以创建多个 HttpContext,一个 HttpContext 对应一个 HttpHandler,不同的 URI 请求,根据添加的 HttpContext 监听器,分配到对应的 HttpHandler 处理请求。

PS: 一个 HTTP 请求只会被一个“最匹配”的 HttpContext 处理。

创建 HTTP 上下文监听器:

HttpServer httpServer = HttpServer.create(...);

/*
 * 上下文监听器对应的 URI 根路径,必须以 "/" 开头,
 * 表示以 "/xxx" 开头的 URI 请求都交给对应的 httpHandler 处理,
 * "/" 表示匹配所有的请求, 一个请求只会交给 path 最匹配的一个上下文去处理(不能重复处理)
 */
String path = "/xxx";

// 可以创建多个,以实现更细致的 URI 路径匹配来分开处理来自不同 URI 路径的请求
httpServer.createContext(path, new HttpHandler() {
    @Override
    public void handle(HttpExchange httpExchange) throws IOException {
        // 处理匹配当前上下文 path 的请求
    }
});

请求 URI 的根路径匹配关系:

Context Context path
ctx1 “/”
ctx2 “/apps/”
ctx3 “/apps/foo/”
Request URI Matches context Context path
http://foo.com/apps/foo/bar ctx3 “/apps/foo/”
http://foo.com/apps/Foo/bar no match, wrong case
http://foo.com/apps/app1 ctx2 “/apps/”
http://foo.com/foo ctx1 “/”

4. 处理器: HttpHandler ( HttpExchange )

HttpHandler 是 HttpContext 对应的请求处理监听器,监听器回调时传入的HttpExchange对象封装了对 http 请求和响应的所有数据操作。

HttpExchange 与 请求 相关的方法:

// 获取请求的 URI, 请求链接除去协议和域名端口后的部分, 如: http://www.abc.com/aa/bb, URI 为 /aa/bb
URI getRequestURI​()

// 获取请求客户端的 IP 地址
InetSocketAddress getRemoteAddress​()

// 获取请求协议, 例如: HTTP/1.1
String getProtocol​()

// 获取请求的方法, "GET", "POST" 等
String getRequestMethod​()

// 获取所有的请求头
Headers getRequestHeaders​()

// 以输入流的方式获取请求内容
InputStream getRequestBody​()

HttpExchange 与 响应 相关的方法:

// 获取响应头的 Map, 要添加头, 获取到 headers 后调用 add(key, value) 方法添加
Headers getResponseHeaders​()

// 发送响应头, 并指定 响应code 和 响应内容的长度
void sendResponseHeaders​(int rCode, long responseLength)

// 获取响应内容的输出流, 响应内容写到该流
OutputStream getResponseBody​()

HttpExchange 其他方法:

// 关闭处理器, 同时将关闭请求和响应的输入输出流(如果还没关闭)
void close​()

// 获取此请求对应的上下文对象
HttpContext getHttpContext​()

// 获取收到请求的本地地址
InetSocketAddress getLocalAddress​()

5. 代码实例

package com.xiets.swing;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import java.io.IOException;
import java.net.InetSocketAddress;

public class Main {

    public static void main(String[] args) throws Exception {
        // 创建 http 服务器, 绑定本地 8080 端口
        HttpServer httpServer = HttpServer.create(new InetSocketAddress(8080), 0);

        // 创上下文监听, "/" 表示匹配所有 URI 请求
        httpServer.createContext("/", new HttpHandler() {
            @Override
            public void handle(HttpExchange httpExchange) throws IOException {
                System.out.println("addr: " + httpExchange.getRemoteAddress() +     // 客户端IP地址
                        "; protocol: " + httpExchange.getProtocol() +               // 请求协议: HTTP/1.1
                        "; method: " + httpExchange.getRequestMethod() +            // 请求方法: GET, POST 等
                        "; URI: " + httpExchange.getRequestURI());                  // 请求 URI

                // 获取请求头
                String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
                System.out.println("User-Agent: " + userAgent);

                // 响应内容
                byte[] respContents = "Hello World".getBytes("UTF-8");

                // 设置响应头
                httpExchange.getResponseHeaders().add("Content-Type", "text/html; charset=UTF-8");
                // 设置响应code和内容长度
                httpExchange.sendResponseHeaders(200, respContents.length);

                // 设置响应内容
                httpExchange.getResponseBody().write(respContents);

                // 关闭处理器
                httpExchange.close();
            }
        });

        // 创建上下文监听, 处理 URI 以 "/aa" 开头的请求
        httpServer.createContext("/aa", new HttpHandler() {
            @Override
            public void handle(HttpExchange httpExchange) throws IOException {
                byte[] respContents = "Hello World AA".getBytes("UTF-8");

                httpExchange.getResponseHeaders().add("Content-Type", "text/html; charset=UTF-8");
                httpExchange.sendResponseHeaders(200, respContents.length);

                httpExchange.getResponseBody().write(respContents);
                httpExchange.close();
            }
        });

        // 启动服务
        httpServer.start();
    }

}

浏览器访问: http://localhost:8080/http://localhost:8080/bb,输出: Hello World

浏览器访问: http://localhost:8080/aahttp://localhost:8080/aa/bb,输出: Hello World AA

猜你喜欢

转载自blog.csdn.net/xietansheng/article/details/78704783