diff --git a/web-service/src/main/java/cn/qaiu/lz/AppMain.java b/web-service/src/main/java/cn/qaiu/lz/AppMain.java index 933a0f5..7e0d30a 100644 --- a/web-service/src/main/java/cn/qaiu/lz/AppMain.java +++ b/web-service/src/main/java/cn/qaiu/lz/AppMain.java @@ -81,6 +81,9 @@ public class AppMain { loadPlaygroundParsers(); String addr = jsonObject.getJsonObject(ConfigConstant.SERVER).getString("domainName"); + if (addr == null || addr.isBlank()) { + addr = "http://127.0.0.1:" + jsonObject.getJsonObject(ConfigConstant.SERVER).getInteger("port", 6400); + } System.out.println("启动成功: \n本地服务地址: " + addr); }); }); diff --git a/web-service/src/main/java/cn/qaiu/lz/common/util/URLParamUtil.java b/web-service/src/main/java/cn/qaiu/lz/common/util/URLParamUtil.java index 64e707c..f761094 100644 --- a/web-service/src/main/java/cn/qaiu/lz/common/util/URLParamUtil.java +++ b/web-service/src/main/java/cn/qaiu/lz/common/util/URLParamUtil.java @@ -119,11 +119,17 @@ public class URLParamUtil { } String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); - parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix); + if (StringUtils.isBlank(linkPrefix)) { + // 未配置 domainName 时,从请求地址推断 + linkPrefix = parserCreate.getShareLinkInfo().getOtherParam() + .getOrDefault("_requestOrigin", "").toString(); + } + if (StringUtils.isNotBlank(linkPrefix)) { + parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix); + } } /** - * 添加临时认证参数(一次性,不保存到数据库或共享内存) * 如果提供了临时认证参数,将覆盖后台配置的认证信息 * * @param parserCreate ParserCreate对象 @@ -155,7 +161,13 @@ public class URLParamUtil { } String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); - parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix); + if (StringUtils.isBlank(linkPrefix)) { + linkPrefix = parserCreate.getShareLinkInfo().getOtherParam() + .getOrDefault("_requestOrigin", "").toString(); + } + if (StringUtils.isNotBlank(linkPrefix)) { + parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix); + } // 构建临时认证信息 MultiMap tempAuth = MultiMap.caseInsensitiveMultiMap(); diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java index e413333..1c20d7c 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java @@ -43,6 +43,30 @@ public class ParserApi { private final DbService dbService = AsyncServiceUtil.getAsyncServiceInstance(DbService.class); + /** + * 获取链接前缀:优先用配置的 domainName,未配置则从请求头推断 + * 支持反向代理:优先读 X-Forwarded-Host/X-Forwarded-Proto,再回退到 Host 头 + */ + private static String getLinkPrefix(HttpServerRequest request) { + String domainName = SharedDataUtil.getJsonConfig("server").getString("domainName"); + if (StringUtils.isNotBlank(domainName)) { + return domainName; + } + if (request != null) { + // 反向代理场景:优先从转发头获取原始域名 + String forwardedHost = request.getHeader("X-Forwarded-Host"); + if (StringUtils.isNotBlank(forwardedHost)) { + String proto = request.getHeader("X-Forwarded-Proto"); + if (StringUtils.isBlank(proto)) { + proto = request.scheme(); + } + return proto + "://" + forwardedHost; + } + return request.scheme() + "://" + request.host(); + } + return ""; + } + @RouteMapping(value = "/statisticsInfo", method = RouteMethod.GET, order = 99) public Future statisticsInfo() { @@ -62,9 +86,9 @@ public class ParserApi { // 构建链接信息响应,如果有 auth 参数则附加到链接中 String authSuffix = (auth != null && !auth.isEmpty()) ? "&auth=" + auth : ""; LinkInfoResp build = LinkInfoResp.builder() - .downLink(getDownLink(parserCreate, false) + authSuffix) - .apiLink(getDownLink(parserCreate, true) + authSuffix) - .viewLink(getViewLink(parserCreate) + authSuffix) + .downLink(getDownLink(parserCreate, false, request) + authSuffix) + .apiLink(getDownLink(parserCreate, true, request) + authSuffix) + .viewLink(getViewLink(parserCreate, request) + authSuffix) .shareLinkInfo(shareLinkInfo).build(); // 解析次数统计 shareLinkInfo.getOtherParam().put("UA",request.headers().get("user-agent")); @@ -82,9 +106,8 @@ public class ParserApi { return promise.future(); } - private static String getDownLink(ParserCreate create, boolean isJson) { - - String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); + private static String getDownLink(ParserCreate create, boolean isJson, HttpServerRequest request) { + String linkPrefix = getLinkPrefix(request); if (StringUtils.isBlank(linkPrefix)) { linkPrefix = "http://127.0.0.1"; } @@ -92,9 +115,8 @@ public class ParserApi { return linkPrefix + (isJson ? "/json/" : "/d/") + create.genPathSuffix(); } - private static String getViewLink(ParserCreate create) { - - String linkPrefix = SharedDataUtil.getJsonStringForServerConfig("domainName"); + private static String getViewLink(ParserCreate create, HttpServerRequest request) { + String linkPrefix = getLinkPrefix(request); if (StringUtils.isBlank(linkPrefix)) { return ""; } @@ -119,7 +141,7 @@ public class ParserApi { public Future> getFileList(HttpServerRequest request, String pwd, String dirId, String uuid) { String url = URLParamUtil.parserParams(request); ParserCreate parserCreate = ParserCreate.fromShareUrl(url).setShareLinkInfoPwd(pwd); - String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); + String linkPrefix = getLinkPrefix(request); parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix); if (StringUtils.isNotBlank(dirId)) { parserCreate.getShareLinkInfo().getOtherParam().put("dirId", dirId); @@ -132,7 +154,7 @@ public class ParserApi { // 目录解析下载文件 // @RouteMapping("/getFileDownUrl/:type/:param") - public Future getFileDownUrl(String type, String param) { + public Future getFileDownUrl(HttpServerRequest request, String type, String param) { ParserCreate parserCreate = ParserCreate.fromType(type).shareKey("-") // shareKey not null .setShareLinkInfoPwd("-"); @@ -147,16 +169,16 @@ public class ParserApi { shareLinkInfo.getOtherParam().put("paramJson", new JsonObject(paramStr)); // domainName - String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); + String linkPrefix = getLinkPrefix(request); shareLinkInfo.getOtherParam().put("domainName", linkPrefix); return parserCreate.createTool().parseById(); } @RouteMapping("/redirectUrl/:type/:param") - public Future redirectUrl(HttpServerResponse response, String type, String param) { + public Future redirectUrl(HttpServerRequest request, HttpServerResponse response, String type, String param) { Promise promise = Promise.promise(); - getFileDownUrl(type, param) + getFileDownUrl(request, type, param) .onSuccess(res -> { ResponseUtil.redirect(response, res); promise.complete(); @@ -232,11 +254,11 @@ public class ParserApi { @RouteMapping("/viewUrl/:type/:param") - public Future viewUrl(HttpServerResponse response, String type, String param) { + public Future viewUrl(HttpServerRequest request, HttpServerResponse response, String type, String param) { Promise promise = Promise.promise(); String viewPrefix = SharedDataUtil.getJsonConfig("server").getString("previewURL"); - getFileDownUrl(type, param) + getFileDownUrl(request, type, param) .onSuccess(res -> { String url = viewPrefix + URLEncoder.encode(res, StandardCharsets.UTF_8); ResponseUtil.redirect(response, url); diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/ServerApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/ServerApi.java index baeae2e..0d4bd5d 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/ServerApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/ServerApi.java @@ -68,7 +68,8 @@ public class ServerApi { key = keys[0]; pwd = keys[1]; } - return cacheService.getCachedByShareKeyAndPwd(type, key, pwd, JsonObject.of("UA",request.headers().get("user-agent"))); + String origin = request.scheme() + "://" + request.host(); + return cacheService.getCachedByShareKeyAndPwd(type, key, pwd, JsonObject.of("UA",request.headers().get("user-agent"), "_requestOrigin", origin)); } @RouteMapping(value = "/:type/:key", method = RouteMethod.GET) @@ -80,7 +81,8 @@ public class ServerApi { key = keys[0]; pwd = keys[1]; } - cacheService.getCachedByShareKeyAndPwd(type, key, pwd, JsonObject.of("UA",request.headers().get("user-agent"))) + String origin = request.scheme() + "://" + request.host(); + cacheService.getCachedByShareKeyAndPwd(type, key, pwd, JsonObject.of("UA",request.headers().get("user-agent"), "_requestOrigin", origin)) .onSuccess(res -> ResponseUtil.redirect( response.putHeader("nfd-cache-hit", res.getCacheHit().toString()) .putHeader("nfd-cache-expires", res.getExpires()), @@ -97,7 +99,8 @@ public class ServerApi { * @return JsonObject */ private JsonObject buildOtherParam(HttpServerRequest request, String auth) { - JsonObject otherParam = JsonObject.of("UA", request.headers().get("user-agent")); + String requestOrigin = request.scheme() + "://" + request.host(); + JsonObject otherParam = JsonObject.of("UA", request.headers().get("user-agent"), "_requestOrigin", requestOrigin); // 解码认证参数 if (auth != null && !auth.isEmpty()) { diff --git a/web-service/src/main/resources/app-dev.yml b/web-service/src/main/resources/app-dev.yml index be00c33..10442da 100644 --- a/web-service/src/main/resources/app-dev.yml +++ b/web-service/src/main/resources/app-dev.yml @@ -4,8 +4,8 @@ server: contextPath: / # 使用数据库 enableDatabase: true - # 服务域名或者IP 生成二维码链接时需要 - domainName: http://127.0.0.1:6401 + # 服务域名或者IP 生成二维码链接时需要,不设置则自动从请求地址获取 +# domainName: http://127.0.0.1:6401 # 预览服务URL previewURL: https://nfd-parser.github.io/nfd-preview/preview.html?src= # auth参数加密密钥(16位AES密钥)