feat: domainName 改为可选,未配置时自动从请求地址推断

- app-dev.yml 注释掉默认 domainName
- ParserApi 添加 getLinkPrefix() 支持 X-Forwarded-Host 反向代理
- ServerApi 传递 _requestOrigin 到 otherParam 供 parser 层使用
- URLParamUtil.addParam() 读不到配置时用 _requestOrigin 兜底
- AppMain 启动日志 domainName 为空时显示本地端口地址
This commit is contained in:
yukaidi
2026-05-29 11:27:32 +08:00
parent e2dc611aa4
commit e1bf45b5c8
5 changed files with 64 additions and 24 deletions

View File

@@ -81,6 +81,9 @@ public class AppMain {
loadPlaygroundParsers(); loadPlaygroundParsers();
String addr = jsonObject.getJsonObject(ConfigConstant.SERVER).getString("domainName"); 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); System.out.println("启动成功: \n本地服务地址: " + addr);
}); });
}); });

View File

@@ -119,11 +119,17 @@ public class URLParamUtil {
} }
String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); 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对象 * @param parserCreate ParserCreate对象
@@ -155,7 +161,13 @@ public class URLParamUtil {
} }
String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); 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(); MultiMap tempAuth = MultiMap.caseInsensitiveMultiMap();

View File

@@ -43,6 +43,30 @@ public class ParserApi {
private final DbService dbService = AsyncServiceUtil.getAsyncServiceInstance(DbService.class); 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) @RouteMapping(value = "/statisticsInfo", method = RouteMethod.GET, order = 99)
public Future<StatisticsInfo> statisticsInfo() { public Future<StatisticsInfo> statisticsInfo() {
@@ -62,9 +86,9 @@ public class ParserApi {
// 构建链接信息响应,如果有 auth 参数则附加到链接中 // 构建链接信息响应,如果有 auth 参数则附加到链接中
String authSuffix = (auth != null && !auth.isEmpty()) ? "&auth=" + auth : ""; String authSuffix = (auth != null && !auth.isEmpty()) ? "&auth=" + auth : "";
LinkInfoResp build = LinkInfoResp.builder() LinkInfoResp build = LinkInfoResp.builder()
.downLink(getDownLink(parserCreate, false) + authSuffix) .downLink(getDownLink(parserCreate, false, request) + authSuffix)
.apiLink(getDownLink(parserCreate, true) + authSuffix) .apiLink(getDownLink(parserCreate, true, request) + authSuffix)
.viewLink(getViewLink(parserCreate) + authSuffix) .viewLink(getViewLink(parserCreate, request) + authSuffix)
.shareLinkInfo(shareLinkInfo).build(); .shareLinkInfo(shareLinkInfo).build();
// 解析次数统计 // 解析次数统计
shareLinkInfo.getOtherParam().put("UA",request.headers().get("user-agent")); shareLinkInfo.getOtherParam().put("UA",request.headers().get("user-agent"));
@@ -82,9 +106,8 @@ public class ParserApi {
return promise.future(); return promise.future();
} }
private static String getDownLink(ParserCreate create, boolean isJson) { private static String getDownLink(ParserCreate create, boolean isJson, HttpServerRequest request) {
String linkPrefix = getLinkPrefix(request);
String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName");
if (StringUtils.isBlank(linkPrefix)) { if (StringUtils.isBlank(linkPrefix)) {
linkPrefix = "http://127.0.0.1"; linkPrefix = "http://127.0.0.1";
} }
@@ -92,9 +115,8 @@ public class ParserApi {
return linkPrefix + (isJson ? "/json/" : "/d/") + create.genPathSuffix(); return linkPrefix + (isJson ? "/json/" : "/d/") + create.genPathSuffix();
} }
private static String getViewLink(ParserCreate create) { private static String getViewLink(ParserCreate create, HttpServerRequest request) {
String linkPrefix = getLinkPrefix(request);
String linkPrefix = SharedDataUtil.getJsonStringForServerConfig("domainName");
if (StringUtils.isBlank(linkPrefix)) { if (StringUtils.isBlank(linkPrefix)) {
return ""; return "";
} }
@@ -119,7 +141,7 @@ public class ParserApi {
public Future<List<FileInfo>> getFileList(HttpServerRequest request, String pwd, String dirId, String uuid) { public Future<List<FileInfo>> getFileList(HttpServerRequest request, String pwd, String dirId, String uuid) {
String url = URLParamUtil.parserParams(request); String url = URLParamUtil.parserParams(request);
ParserCreate parserCreate = ParserCreate.fromShareUrl(url).setShareLinkInfoPwd(pwd); ParserCreate parserCreate = ParserCreate.fromShareUrl(url).setShareLinkInfoPwd(pwd);
String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); String linkPrefix = getLinkPrefix(request);
parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix); parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix);
if (StringUtils.isNotBlank(dirId)) { if (StringUtils.isNotBlank(dirId)) {
parserCreate.getShareLinkInfo().getOtherParam().put("dirId", dirId); parserCreate.getShareLinkInfo().getOtherParam().put("dirId", dirId);
@@ -132,7 +154,7 @@ public class ParserApi {
// 目录解析下载文件 // 目录解析下载文件
// @RouteMapping("/getFileDownUrl/:type/:param") // @RouteMapping("/getFileDownUrl/:type/:param")
public Future<String> getFileDownUrl(String type, String param) { public Future<String> getFileDownUrl(HttpServerRequest request, String type, String param) {
ParserCreate parserCreate = ParserCreate.fromType(type).shareKey("-") // shareKey not null ParserCreate parserCreate = ParserCreate.fromType(type).shareKey("-") // shareKey not null
.setShareLinkInfoPwd("-"); .setShareLinkInfoPwd("-");
@@ -147,16 +169,16 @@ public class ParserApi {
shareLinkInfo.getOtherParam().put("paramJson", new JsonObject(paramStr)); shareLinkInfo.getOtherParam().put("paramJson", new JsonObject(paramStr));
// domainName // domainName
String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); String linkPrefix = getLinkPrefix(request);
shareLinkInfo.getOtherParam().put("domainName", linkPrefix); shareLinkInfo.getOtherParam().put("domainName", linkPrefix);
return parserCreate.createTool().parseById(); return parserCreate.createTool().parseById();
} }
@RouteMapping("/redirectUrl/:type/:param") @RouteMapping("/redirectUrl/:type/:param")
public Future<Void> redirectUrl(HttpServerResponse response, String type, String param) { public Future<Void> redirectUrl(HttpServerRequest request, HttpServerResponse response, String type, String param) {
Promise<Void> promise = Promise.promise(); Promise<Void> promise = Promise.promise();
getFileDownUrl(type, param) getFileDownUrl(request, type, param)
.onSuccess(res -> { .onSuccess(res -> {
ResponseUtil.redirect(response, res); ResponseUtil.redirect(response, res);
promise.complete(); promise.complete();
@@ -232,11 +254,11 @@ public class ParserApi {
@RouteMapping("/viewUrl/:type/:param") @RouteMapping("/viewUrl/:type/:param")
public Future<Void> viewUrl(HttpServerResponse response, String type, String param) { public Future<Void> viewUrl(HttpServerRequest request, HttpServerResponse response, String type, String param) {
Promise<Void> promise = Promise.promise(); Promise<Void> promise = Promise.promise();
String viewPrefix = SharedDataUtil.getJsonConfig("server").getString("previewURL"); String viewPrefix = SharedDataUtil.getJsonConfig("server").getString("previewURL");
getFileDownUrl(type, param) getFileDownUrl(request, type, param)
.onSuccess(res -> { .onSuccess(res -> {
String url = viewPrefix + URLEncoder.encode(res, StandardCharsets.UTF_8); String url = viewPrefix + URLEncoder.encode(res, StandardCharsets.UTF_8);
ResponseUtil.redirect(response, url); ResponseUtil.redirect(response, url);

View File

@@ -68,7 +68,8 @@ public class ServerApi {
key = keys[0]; key = keys[0];
pwd = keys[1]; 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) @RouteMapping(value = "/:type/:key", method = RouteMethod.GET)
@@ -80,7 +81,8 @@ public class ServerApi {
key = keys[0]; key = keys[0];
pwd = keys[1]; 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( .onSuccess(res -> ResponseUtil.redirect(
response.putHeader("nfd-cache-hit", res.getCacheHit().toString()) response.putHeader("nfd-cache-hit", res.getCacheHit().toString())
.putHeader("nfd-cache-expires", res.getExpires()), .putHeader("nfd-cache-expires", res.getExpires()),
@@ -97,7 +99,8 @@ public class ServerApi {
* @return JsonObject * @return JsonObject
*/ */
private JsonObject buildOtherParam(HttpServerRequest request, String auth) { 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()) { if (auth != null && !auth.isEmpty()) {

View File

@@ -4,8 +4,8 @@ server:
contextPath: / contextPath: /
# 使用数据库 # 使用数据库
enableDatabase: true enableDatabase: true
# 服务域名或者IP 生成二维码链接时需要 # 服务域名或者IP 生成二维码链接时需要,不设置则自动从请求地址获取
domainName: http://127.0.0.1:6401 # domainName: http://127.0.0.1:6401
# 预览服务URL # 预览服务URL
previewURL: https://nfd-parser.github.io/nfd-preview/preview.html?src= previewURL: https://nfd-parser.github.io/nfd-preview/preview.html?src=
# auth参数加密密钥16位AES密钥 # auth参数加密密钥16位AES密钥