diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/HttpRequestHandler.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/HttpRequestHandler.java index 515e7ca7..f29f402f 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/HttpRequestHandler.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/HttpRequestHandler.java @@ -32,6 +32,7 @@ import fun.asgc.neutrino.core.web.annotation.RequestBody; import fun.asgc.neutrino.core.web.annotation.RequestParam; import fun.asgc.neutrino.core.web.param.HttpContextHolder; import fun.asgc.neutrino.core.web.param.HttpRequestParser; +import fun.asgc.neutrino.core.web.param.WebContextHolder; import fun.asgc.neutrino.core.web.router.DefaultHttpRouter; import fun.asgc.neutrino.core.web.router.HttpRouteParam; import fun.asgc.neutrino.core.web.router.HttpRouteResult; @@ -61,59 +62,60 @@ public class HttpRequestHandler { private ApplicationConfig applicationConfig; @Autowired private DefaultHttpRouter defaultHttpRouter; - private static volatile String httpContextPath; public void handle() { ChannelHandlerContext context = HttpContextHolder.getChannelHandlerContext(); HttpRequestParser requestParser = HttpContextHolder.getHttpRequestParser(); log.info("HttpRequest method:{} url:{} query:{}", requestParser.getMethod().name(), requestParser.getUrl(), requestParser.getQueryParamMap()); - String routePath = getRoutePath(requestParser.getUrl()); - HttpMethod httpMethod = HttpMethod.of(requestParser.getMethod().name()); - HttpRouteResult httpRouteResult = defaultHttpRouter.route(new HttpRouteParam().setMethod(httpMethod).setUrl(routePath)); - if (null == httpRouteResult) { - HttpServerUtil.send404Response(context, requestParser.getUrl()); - release(); - return; - } - if (HttpRouterType.METHOD == httpRouteResult.getType()) { - try { - Object invokeResult = invoke(httpRouteResult.getInstance(), httpRouteResult.getMethod()); - String res = String.valueOf(invokeResult); - if (null != invokeResult && !TypeUtil.isNormalBasicType(invokeResult.getClass())) { - res = JSONObject.toJSONString(invokeResult); + try { + String routePath = requestParser.getRoutePath(); + HttpMethod httpMethod = HttpMethod.of(requestParser.getMethod().name()); + HttpRouteResult httpRouteResult = defaultHttpRouter.route(new HttpRouteParam().setMethod(httpMethod).setUrl(routePath)); + if (null == httpRouteResult) { + HttpServerUtil.send404Response(context, requestParser.getUrl()); + return; + } + if (HttpRouterType.METHOD == httpRouteResult.getType()) { + + Object invokeResult = invoke(httpRouteResult.getInstance(), httpRouteResult.getMethod()); + String res = String.valueOf(invokeResult); + if (null != invokeResult && !TypeUtil.isNormalBasicType(invokeResult.getClass())) { + res = JSONObject.toJSONString(invokeResult); + } + FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(res.getBytes())); + fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + context.writeAndFlush(fullHttpResponse).addListener(ChannelFutureListener.CLOSE); + return; + } else if(HttpRouterType.PAGE == httpRouteResult.getType()) { + // 前端页面 + String mimeType = MimeType.getMimeType(MimeType.parseSuffix(httpRouteResult.getPageLocation())); + if (mimeType.startsWith("text/")) { + mimeType += ";charset=utf-8"; } - FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(res.getBytes())); - fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(FileUtil.readBytes(httpRouteResult.getPageLocation()))); + fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, mimeType); + fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_LANGUAGE, "zh-CN"); + fullHttpResponse.headers().add(HttpHeaderNames.SERVER, MetaDataConstant.SERVER_VS); + fullHttpResponse.headers().add(HttpHeaderNames.DATE, new Date()); context.writeAndFlush(fullHttpResponse).addListener(ChannelFutureListener.CLOSE); return; - } catch (Exception e) { - log.error("Http处理异常", e); - } finally { - release(); + } else { + HttpServerUtil.send404Response(context, requestParser.getUrl()); + return; } - } else if(HttpRouterType.PAGE == httpRouteResult.getType()) { - // 前端页面 - String mimeType = MimeType.getMimeType(MimeType.parseSuffix(httpRouteResult.getPageLocation())); - if (mimeType.startsWith("text/")) { - mimeType += ";charset=utf-8"; - } - FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(FileUtil.readBytes(httpRouteResult.getPageLocation()))); - fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, mimeType); - fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_LANGUAGE, "zh-CN"); - fullHttpResponse.headers().add(HttpHeaderNames.SERVER, MetaDataConstant.SERVER_VS); - fullHttpResponse.headers().add(HttpHeaderNames.DATE, new Date()); - context.writeAndFlush(fullHttpResponse).addListener(ChannelFutureListener.CLOSE); + } catch (Throwable e) { + exceptionHandler(e); + } finally { release(); - return; - } else { - // TODO - HttpServerUtil.send404Response(context, requestParser.getUrl()); - release(); - return; } } + private void exceptionHandler(Throwable e) { + log.error("Http处理异常", e); + HttpServerUtil.send500Response(HttpContextHolder.getChannelHandlerContext(), e); + } + private Object invoke(Object instance, Method method) throws InvocationTargetException, IllegalAccessException { Object[] params = new Object[method.getParameterCount()]; if (method.getParameterCount() > 0) { @@ -155,36 +157,4 @@ public class HttpRequestHandler { private void release() { HttpContextHolder.remove(); } - - private String getRoutePath(String url) { - String httpContextPath = getHttpContextPath(); - if (StringUtil.isEmpty(httpContextPath)) { - return url; - } - String res = url.substring(httpContextPath.length()); - if (StringUtil.isEmpty(res)) { - return "/"; - } - return res; - } - - private String getHttpContextPath() { - return LockUtil.doubleCheckProcessForNoException( - () -> null == httpContextPath, - this, - () -> { - httpContextPath = applicationConfig.getHttp().getContextPath(); - if (StringUtil.isEmpty(httpContextPath)) { - httpContextPath = "/"; - } - if (!httpContextPath.startsWith("/")) { - httpContextPath = "/" + httpContextPath; - } - if (httpContextPath.endsWith("/")) { - httpContextPath = httpContextPath.substring(0, httpContextPath.length() - 1); - } - }, - () -> httpContextPath - ); - } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/WebApplicationServer.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/WebApplicationServer.java index 8e13670a..dc5f99ff 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/WebApplicationServer.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/WebApplicationServer.java @@ -29,6 +29,7 @@ import fun.asgc.neutrino.core.context.ApplicationConfig; import fun.asgc.neutrino.core.context.ApplicationRunner; import fun.asgc.neutrino.core.util.*; import fun.asgc.neutrino.core.web.param.HttpContextHolder; +import fun.asgc.neutrino.core.web.param.WebContextHolder; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.*; @@ -55,25 +56,17 @@ public class WebApplicationServer implements ApplicationRunner { private EventLoopGroup workerGroup; private ServerBootstrap serverBootstrap; private ChannelFuture channelFuture; - private byte[] faviconBytes; @Init public void init() { - ApplicationConfig.Http http = applicationConfig.getHttp(); - if (StringUtil.notEmpty(http.getMaxContentLengthDesc()) && null == http.getMaxContentLength()) { - http.setMaxContentLength(NumberUtil.descriptionToSize(http.getMaxContentLengthDesc(), 64 * 1024)); - } - + WebContextHolder.init(applicationConfig.getHttp()); this.bossGroup = new NioEventLoopGroup(); this.workerGroup = new NioEventLoopGroup(); this.serverBootstrap = new ServerBootstrap(); - this.initFavicon(); } @Override public void run(String[] args) throws Exception { - ApplicationConfig.Http http = applicationConfig.getHttp(); - this.serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) @@ -86,7 +79,7 @@ public class WebApplicationServer implements ApplicationRunner { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new ChunkedWriteHandler()); - pipeline.addLast(new HttpObjectAggregator(http.getMaxContentLength().intValue())); + pipeline.addLast(new HttpObjectAggregator(WebContextHolder.getMaxContentLength().intValue())); pipeline.addLast(new SimpleChannelInboundHandler() { @Override protected void channelRead0(ChannelHandlerContext context, FullHttpRequest request) throws Exception { @@ -94,10 +87,10 @@ public class WebApplicationServer implements ApplicationRunner { String uri = request.uri(); log.debug("http request: {}", uri); - if (http.getContextPath().equals("/") || uri.startsWith(http.getContextPath() + "/") || uri.equals(http.getContextPath())) { + if (WebContextHolder.getHttpContextPath().equals("/") || uri.startsWith(WebContextHolder.getHttpContextPath() + "/") || uri.equals(WebContextHolder.getHttpContextPath())) { httpRequestHandler.handle(); - } else if (uri.equals("/favicon.ico") && null != faviconBytes) { - FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(faviconBytes)); + } else if (uri.equals("/favicon.ico") && null != WebContextHolder.getFaviconBytes()) { + FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(WebContextHolder.getFaviconBytes())); fullHttpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, "image/x-icon"); context.writeAndFlush(fullHttpResponse).addListener(ChannelFutureListener.CLOSE); } else { @@ -107,20 +100,8 @@ public class WebApplicationServer implements ApplicationRunner { }); } }); - channelFuture = this.serverBootstrap.bind(http.getPort()).sync(); - log.info("HTTP服务启动,端口:{} context-path:{}", http.getPort(), http.getContextPath()); - } - - private void initFavicon() { - if (null == applicationConfig.getHttp().getStaticResource() || CollectionUtil.isEmpty(applicationConfig.getHttp().getStaticResource().getLocations())) { - return; - } - for (String location : applicationConfig.getHttp().getStaticResource().getLocations()) { - this.faviconBytes = FileUtil.readBytes(location.concat("favicon.ico")); - if (null != faviconBytes) { - break; - } - } + channelFuture = this.serverBootstrap.bind(WebContextHolder.getPort()).sync(); + log.info("HTTP服务启动,端口:{} context-path:{}", WebContextHolder.getPort(), WebContextHolder.getHttpContextPath()); } @Destroy diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/param/HttpRequestParser.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/param/HttpRequestParser.java index 26fd8a67..cb8d718c 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/param/HttpRequestParser.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/param/HttpRequestParser.java @@ -43,6 +43,7 @@ public class HttpRequestParser { private String url; private String queryString; private Map queryParamMap = null; + private String routePath; private HttpRequestParser(FullHttpRequest request) { this.request = request; @@ -56,6 +57,7 @@ public class HttpRequestParser { } url = getUrl().substring(0, index); } + this.routePath = getRoutePath(url); } public static HttpRequestParser create(FullHttpRequest request) { @@ -66,6 +68,10 @@ public class HttpRequestParser { return url; } + public String getRoutePath() { + return routePath; + } + public String getQueryString() { return queryString; } @@ -170,4 +176,16 @@ public class HttpRequestParser { } return result; } + + private String getRoutePath(String url) { + String httpContextPath = WebContextHolder.getHttpContextPath(); + if (StringUtil.isEmpty(httpContextPath)) { + return url; + } + String res = url.substring(httpContextPath.length()); + if (StringUtil.isEmpty(res)) { + return "/"; + } + return res; + } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/param/WebContextHolder.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/param/WebContextHolder.java new file mode 100644 index 00000000..189b2877 --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/web/param/WebContextHolder.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.web.param; + +import fun.asgc.neutrino.core.context.ApplicationConfig; +import fun.asgc.neutrino.core.util.*; + +/** + * + * @author: aoshiguchen + * @date: 2022/7/26 + */ +public abstract class WebContextHolder { + private static ApplicationConfig.Http http; + private static volatile String httpContextPath; + private static volatile byte[] faviconBytes; + private static volatile Long maxContentLength; + private static volatile Integer port; + + public static void init(ApplicationConfig.Http http) { + Assert.notNull(http, "http配置不能为空!"); + WebContextHolder.http = http; + initHttpContextPath(); + initFavicon(); + initMaxContentLength(); + port = http.getPort(); + } + + public static String getHttpContextPath() { + return httpContextPath; + } + + public static byte[] getFaviconBytes() { + return faviconBytes; + } + + public static Long getMaxContentLength() { + return maxContentLength; + } + + public static Integer getPort() { + return port; + } + + private static void initHttpContextPath() { + httpContextPath = http.getContextPath(); + if (StringUtil.isEmpty(httpContextPath)) { + httpContextPath = "/"; + } + if (!httpContextPath.startsWith("/")) { + httpContextPath = "/" + httpContextPath; + } + if (httpContextPath.endsWith("/")) { + httpContextPath = httpContextPath.substring(0, httpContextPath.length() - 1); + } + } + + private static void initFavicon() { + if (null == http.getStaticResource() || CollectionUtil.isEmpty(http.getStaticResource().getLocations())) { + return; + } + for (String location : http.getStaticResource().getLocations()) { + faviconBytes = FileUtil.readBytes(location.concat("favicon.ico")); + if (null != faviconBytes) { + break; + } + } + } + + private static void initMaxContentLength() { + maxContentLength = http.getMaxContentLength(); + if (StringUtil.notEmpty(http.getMaxContentLengthDesc()) && null == http.getMaxContentLength()) { + maxContentLength = NumberUtil.descriptionToSize(http.getMaxContentLengthDesc(), 64 * 1024); + } + } +} diff --git a/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/controller/Test1Controller.java b/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/controller/Test1Controller.java index eac65fa0..3decf67d 100644 --- a/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/controller/Test1Controller.java +++ b/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/controller/Test1Controller.java @@ -41,7 +41,10 @@ public class Test1Controller { @GetMapping("hello") public String hello() { - System.out.println("拿到参数 a = " + HttpContextHolder.getHttpRequestParser().getParameterForInteger("a")); + System.out.println("拿到参数 a = " + HttpContextHolder.getHttpRequestParser().getParameter("a")); + if ("aaa".equals(HttpContextHolder.getHttpRequestParser().getParameter("a"))) { + throw new RuntimeException("hhhh 异常了!"); + } return test1Service.hello(); }