Netty设置为Https访问
SSLContextFactory
public class SSLContextFactory { public static SSLContext getSslContext() throws Exception { char[] passArray = "zhuofansoft".toCharArray(); SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); KeyStore ks = KeyStore.getInstance("JKS"); //鍔犺浇keytool 鐢熸垚鐨勬枃浠� FileInputStream inputStream = new FileInputStream("D://server.keystore"); ks.load(inputStream, passArray); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, passArray); sslContext.init(kmf.getKeyManagers(), null, null); inputStream.close(); return sslContext; } }
处理类
public class HttpsSeverHandler extends ChannelInboundHandlerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(HttpServerHandler.class); @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof HttpRequest) { HttpRequest request = (HttpRequest) msg; LOGGER.info("access messageReceived invoke success.."); Long startTime = System.currentTimeMillis(); // 400 if (!request.decoderResult().isSuccess()) { sendError(ctx, HttpResponseStatus.BAD_REQUEST); return; } // 405 if (request.method() != GET) { sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED); return; } FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.OK); MapparmMap = new RequestParser((FullHttpRequest) request).parse(); //jQuery跨域携带标识符 String callback = parmMap.get("callback"); LOGGER.info("connection jsonp header:[{}],request param:[{}]",callback,parmMap.get("requestParam"));; //请求参数 DeviceRequest deviceRequest = JSONObject.parseObject(parmMap.get("requestParam"), DeviceRequest.class); DeviceResultWapper> result = getClientResponse(deviceRequest); LOGGER.info("get client response success.. response:[{}]",JSONObject.toJSONString(result)); LOGGER.info("get client response take time:[{}]",(System.currentTimeMillis()-startTime)/1000+"s"); String content = callback + "("+JSONObject.toJSONString(result)+")"; byte[] bs = content.getBytes("UTF-8"); response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(bs.length)); response.content().writeBytes(ByteBuffer.wrap(bs)); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); /* HttpRequest request = (HttpRequest) msg; boolean keepaLive = HttpUtil.isKeepAlive(request); System.out.println("method" + request.method()); System.out.println("uri" + request.uri()); FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); httpResponse.content().writeBytes("https".getBytes()); httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=UTF-8"); httpResponse.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes()); if (keepaLive) { httpResponse.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); ctx.writeAndFlush(httpResponse); } else { ctx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE); }*/ } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); if (ctx.channel().isActive()) { sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR); } } private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8)); response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } /* @Override protected void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { LOGGER.info("access messageReceived invoke success.."); Long startTime = System.currentTimeMillis(); // 400 if (!request.decoderResult().isSuccess()) { sendError(ctx, HttpResponseStatus.BAD_REQUEST); return; } // 405 if (request.method() != GET) { sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED); return; } FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.OK); Map parmMap = new RequestParser(request).parse(); //jQuery跨域携带标识符 String callback = parmMap.get("callback"); LOGGER.info("connection jsonp header:[{}],request param:[{}]",callback,parmMap.get("requestParam"));; //请求参数 DeviceRequest deviceRequest = JSONObject.parseObject(parmMap.get("requestParam"), DeviceRequest.class); DeviceResultWapper> result = getClientResponse(deviceRequest); LOGGER.info("get client response success.. response:[{}]",JSONObject.toJSONString(result)); LOGGER.info("get client response take time:[{}]",(System.currentTimeMillis()-startTime)/1000+"s"); String content = callback + "("+JSONObject.toJSONString(result)+")"; byte[] bs = content.getBytes("UTF-8"); response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(bs.length)); response.content().writeBytes(ByteBuffer.wrap(bs)); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } */ private DeviceResultWapper> getClientResponse(DeviceRequest deviceRequest) { // 拼接参数 DeviceCommandVo deviceCommandVo = DeviceType.wapperRequestParam(deviceRequest); if (deviceCommandVo == null) { return DeviceResultWapper.fail(400, "remote user with illegal param"); } SerialPortOrder serialPortOrder = DeviceOrderFactory.produce(deviceCommandVo.getDeviceTypeId()); return serialPortOrder.order(deviceCommandVo); } }
Netty实现Http协议
这里简单介绍下,项目中使用netty在main方法中启动项目,实现http协议。
maven依赖的包
io.netty netty-all 4.1.27.Final
1.netty启动入口
package com.fotile.cloud.ruleengin; import javax.servlet.ServletException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.mock.web.MockServletConfig; import org.springframework.web.context.support.XmlWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import com.fotile.cloud.ruleengin.falsework.NettyHttpServer; /** * Hello world! * */ public class RuleApplication { // 引擎端口 private final static int ENGINE_PORT = 8086; /** * http prot is 8085, */ public static void main(String[] args) { // 加载spring配置 ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml"); DispatcherServlet servlet = getDispatcherServlet(ctx); NettyHttpServer server = new NettyHttpServer(ENGINE_PORT, servlet); server.start(); } public static DispatcherServlet getDispatcherServlet(ApplicationContext ctx) { XmlWebApplicationContext mvcContext = new XmlWebApplicationContext(); // 加载spring-mvc配置 mvcContext.setConfigLocation("classpath:spring-mvc.xml"); mvcContext.setParent(ctx); MockServletConfig servletConfig = new MockServletConfig(mvcContext.getServletContext(), "dispatcherServlet"); DispatcherServlet dispatcherServlet = new DispatcherServlet(mvcContext); try { dispatcherServlet.init(servletConfig); } catch (ServletException e) { e.printStackTrace(); } return dispatcherServlet; } }
2.编写NettyHttpServer
package com.fotile.cloud.openplatform.falsework; import org.apache.log4j.Logger; import org.springframework.web.servlet.DispatcherServlet; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; public class NettyHttpServer implements Runnable { private Logger LOGGER = Logger.getLogger(this.getClass()); private int port; private DispatcherServlet servlet; public NettyHttpServer(Integer port) { this.port = port; } public NettyHttpServer(Integer port, DispatcherServlet servlet) { this.port = port; this.servlet = servlet; } public void start() { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .childHandler(new HttpServerInitializer(servlet)).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); LOGGER.info("NettyHttpServer Run successfully"); // 绑定端口,开始接收进来的连接 ChannelFuture f = b.bind(port).sync(); // 等待服务器 socket 关闭 。在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 f.channel().closeFuture().sync(); } catch (Exception e) { System.out.println("NettySever start fail" + e); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } @Override public void run() { start(); } }
3.处理http请求、处理、返回
package com.fotile.cloud.ruleengin.falsework; import java.net.URLDecoder; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType; import io.netty.handler.codec.http.multipart.MemoryAttribute; import io.netty.util.CharsetUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriUtils; public class HttpRequestHandler extends SimpleChannelInboundHandler{ private DispatcherServlet servlet; public HttpRequestHandler(DispatcherServlet servlet) { this.servlet = servlet; } @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception { boolean flag = HttpMethod.POST.equals(fullHttpRequest.method()) || HttpMethod.GET.equals(fullHttpRequest.method()) || HttpMethod.DELETE.equals(fullHttpRequest.method()) || HttpMethod.PUT.equals(fullHttpRequest.method()); Map parammap = getRequestParams(ctx, fullHttpRequest); if (flag && ctx.channel().isActive()) { // HTTP请求、GET/POST MockHttpServletResponse servletResponse = new MockHttpServletResponse(); MockHttpServletRequest servletRequest = new MockHttpServletRequest( servlet.getServletConfig().getServletContext()); // headers for (String name : fullHttpRequest.headers().names()) { for (String value : fullHttpRequest.headers().getAll(name)) { servletRequest.addHeader(name, value); } } String uri = fullHttpRequest.uri(); uri = new String(uri.getBytes("ISO8859-1"), "UTF-8"); uri = URLDecoder.decode(uri, "UTF-8"); UriComponents uriComponents = UriComponentsBuilder.fromUriString(uri).build(); String path = uriComponents.getPath(); path = URLDecoder.decode(path, "UTF-8"); servletRequest.setRequestURI(path); servletRequest.setServletPath(path); servletRequest.setMethod(fullHttpRequest.method().name()); if (uriComponents.getScheme() != null) { servletRequest.setScheme(uriComponents.getScheme()); } if (uriComponents.getHost() != null) { servletRequest.setServerName(uriComponents.getHost()); } if (uriComponents.getPort() != -1) { servletRequest.setServerPort(uriComponents.getPort()); } ByteBuf content = fullHttpRequest.content(); content.readerIndex(0); byte[] data = new byte[content.readableBytes()]; content.readBytes(data); servletRequest.setContent(data); if (uriComponents.getQuery() != null) { String query = UriUtils.decode(uriComponents.getQuery(), "UTF-8"); servletRequest.setQueryString(query); } if (parammap != null && parammap.size() > 0) { for (String key : parammap.keySet()) { servletRequest.addParameter(UriUtils.decode(key, "UTF-8"), UriUtils.decode(parammap.get(key) == null ? "" : parammap.get(key), "UTF-8")); } } servlet.service(servletRequest, servletResponse); HttpResponseStatus status = HttpResponseStatus.valueOf(servletResponse.getStatus()); String result = servletResponse.getContentAsString(); result = StringUtils.isEmpty(result) ? status.toString() : result; FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(result, CharsetUtil.UTF_8)); response.headers().set("Content-Type", "text/json;charset=UTF-8"); response.headers().set("Access-Control-Allow-Origin", "*"); response.headers().set("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With,X-File-Name"); response.headers().set("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); response.headers().set("Content-Length", Integer.valueOf(response.content().readableBytes())); response.headers().set("Connection", "keep-alive"); ChannelFuture writeFuture = ctx.writeAndFlush(response); writeFuture.addListener(ChannelFutureListener.CLOSE); } } /** * 获取post请求、get请求的参数保存到map中 */ private Map getRequestParams(ChannelHandlerContext ctx, HttpRequest req) { Map requestParams = new HashMap (); // 处理get请求 if (req.method() == HttpMethod.GET) { QueryStringDecoder decoder = new QueryStringDecoder(req.uri()); Map > parame = decoder.parameters(); Iterator >> iterator = parame.entrySet().iterator(); while (iterator.hasNext()) { Entry > next = iterator.next(); requestParams.put(next.getKey(), next.getValue().get(0)); } } // 处理POST请求 if (req.method() == HttpMethod.POST) { HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), req); List postData = decoder.getBodyHttpDatas(); // for (InterfaceHttpData data : postData) { if (data.getHttpDataType() == HttpDataType.Attribute) { MemoryAttribute attribute = (MemoryAttribute) data; requestParams.put(attribute.getName(), attribute.getValue()); } } } return requestParams; } }
启来后,使用postman,调用本地接口。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。