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();
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);
});
});

View File

@@ -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();

View File

@@ -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> 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<List<FileInfo>> 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<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
.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<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();
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<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();
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);

View File

@@ -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()) {

View File

@@ -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密钥