1、Http服务器实现
引导服务
@Slf4j
public class HttpServer {
static final int PORT = 8080;
public static void main(String[] args) throws Exception {
start();
}
public static void start() throws Exception {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workGroup = new NioEventLoopGroup(10);
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_KEEPALIVE, true);
try {
serverBootstrap.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpServerInitializer());
Channel channel = serverBootstrap.bind(PORT).sync().channel();
log.info("HttpServer listening on port " + PORT);
channel.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
添加对Http的支持
@Slf4j
public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
private static final String FAVICON_ICO = "/favicon.ico";
private HttpHeaders headers;
private HttpRequest request;
private FullHttpRequest fullRequest;
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject msg) throws Exception {
if (msg instanceof HttpRequest) {
request = (HttpRequest) msg;
headers = request.headers();
String uri = request.uri();
log.info("request uri:" + uri);
if (FAVICON_ICO.equals(uri)) return;
HttpMethod method = request.method();
if (HttpMethod.GET.equals(method)) {
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri, Charsets.UTF_8);
Map<String, List<String>> parameters = queryStringDecoder.parameters();
log.info("requestParam----> {}", parameters);
} else if (HttpMethod.POST.equals(method)) {
fullRequest = (FullHttpRequest) msg;
dealWithContentType();
}
Student student = new Student();
student.setId("12");
student.setClassNo("05");
student.setName("jim");
String resp = JSONObject.toJSONString(student);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(resp.getBytes()));
response.headers().set("Content-Type", "application/json");
response.headers().set("Content-Length", response.content().readableBytes());
boolean keepAlive = HttpUtil.isKeepAlive(request);
if (!keepAlive) {
channelHandlerContext.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
response.headers().set("Connection", "true");
channelHandlerContext.write(response);
}
} else {
log.info("非法请求");
}
}
private void dealWithContentType() {
String contentType = headers.get("Content-Type").split(";")[0];
if (contentType.equals("application/json")) {
String jsonStr = fullRequest.content().toString(Charsets.UTF_8);
log.info("requestContent--->{}", jsonStr);
} else if (contentType.equals("application/x-www-form-urlencoded")) {
String requestStr = fullRequest.content().toString(Charsets.UTF_8);
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(requestStr, Charsets.UTF_8);
log.info("requestContent--->{}", queryStringDecoder);
} else {
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("HttpServerHandler happened exception", cause);
ctx.close();
}
实现对Https的支持
public class HttpsServerInitializer extends ChannelInitializer {
private SSLContext sslContext;
public HttpsServerInitializer(SSLContext sslContext) {
this.sslContext = sslContext;
}
@Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
channel.pipeline().addLast("ssl", new SslHandler(sslEngine))
.addLast("codec", new HttpServerCodec())
.addLast(new HttpObjectAggregator(1024 * 1024))
.addLast(new HttpServerHandler());
}
}
public class SSLContextFactory {
public static SSLContext getSslContext() throws Exception {
char[] filePass = "123456".toCharArray();
SSLContext sslContext = SSLContext.getInstance("TLSv1.1");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(Files.newInputStream(Paths.get("/tmp/key/test.jks"), StandardOpenOption.READ), filePass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, filePass);
sslContext.init(kmf.getKeyManagers(), null, null);
return sslContext;
}
}
服务端的秘钥可以用JDK提供的keytool生成
在使用Https的需要注意,如果服务端不支持客户端使用的TLS版本,会报javax.net.ssl.SSLException: Received fatal alert: certificate_unknown异常。
可以在启动服务的时候添加JVM参数 -Djavax.net.debug=all,可以查看http握手过程以及客户端使用的TLS版本。
image.png
网友评论