mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-01 00:26:38 +08:00
兼容v6
This commit is contained in:
@@ -237,6 +237,9 @@ go-gost/gost.json
|
||||
|
||||
gitee/
|
||||
|
||||
# 错误位置的Java构建产物
|
||||
java/
|
||||
|
||||
# ==========================================
|
||||
# 其他
|
||||
# ==========================================
|
||||
|
||||
-3
@@ -34,9 +34,6 @@ public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(value = Exception.class)
|
||||
public R Exception(Exception e){
|
||||
if (e instanceof ClientAbortException) {
|
||||
return null; // 不需要返回值
|
||||
}
|
||||
log.error("异常:----------------{}", e.getMessage());
|
||||
return R.err(-2, "异常错误");
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@@ -100,16 +101,34 @@ public class HttpUtils implements ApplicationContextAware {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误处理器,不抛出异常
|
||||
* 自定义错误处理器,不抛出异常但记录错误信息
|
||||
*/
|
||||
private static class NoOpResponseErrorHandler implements ResponseErrorHandler {
|
||||
@Override
|
||||
public boolean hasError(ClientHttpResponse response) throws IOException {
|
||||
return false;
|
||||
HttpStatus statusCode = response.getStatusCode();
|
||||
return statusCode.series() == HttpStatus.Series.CLIENT_ERROR ||
|
||||
statusCode.series() == HttpStatus.Series.SERVER_ERROR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
HttpStatus statusCode = response.getStatusCode();
|
||||
String statusText = response.getStatusText();
|
||||
String responseBody = "";
|
||||
|
||||
try {
|
||||
// 使用Spring的StreamUtils来读取响应体
|
||||
responseBody = new String(
|
||||
StreamUtils.copyToByteArray(response.getBody()),
|
||||
StandardCharsets.UTF_8
|
||||
);
|
||||
} catch (Exception e) {
|
||||
responseBody = "无法读取响应体: " + e.getMessage();
|
||||
}
|
||||
|
||||
logger.error("HTTP请求错误 - 状态码: {} {}, 响应体: {}",
|
||||
statusCode.value(), statusText, responseBody);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -177,13 +177,13 @@
|
||||
<el-form-item label="远程地址" prop="remoteAddr">
|
||||
<el-input
|
||||
v-model="forwardForm.remoteAddr"
|
||||
placeholder="例如: 192.168.1.100:8080"
|
||||
placeholder="例如: 192.168.1.100:8080 或 [2001:db8::1]:8080"
|
||||
clearable
|
||||
>
|
||||
<template slot="prepend">目标</template>
|
||||
</el-input>
|
||||
<div class="form-hint">
|
||||
格式: IP:端口 或 域名:端口
|
||||
格式: IPv4(IP:端口)、IPv6([IPv6]:端口)或域名:端口
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
@@ -254,8 +254,32 @@ export default {
|
||||
remoteAddr: [
|
||||
{ required: true, message: '请输入远程地址', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[\w\.-]+:\d+$/,
|
||||
message: '请输入正确的地址格式,如: 192.168.1.100:8080',
|
||||
validator: (rule, value, callback) => {
|
||||
if (value) {
|
||||
// IPv4格式:192.168.1.1:8080
|
||||
const ipv4Pattern = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):\d+$/;
|
||||
|
||||
// IPv6格式(带方括号):[2001:db8::1]:8080
|
||||
const ipv6BracketPattern = /^\[([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}\]:\d+$/;
|
||||
|
||||
// IPv6格式(简化版本,包括::1, ::, ::ffff:192.0.2.1等)
|
||||
const ipv6SimplifiedPattern = /^\[(::1|::|::ffff:[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|([0-9a-fA-F]{1,4}:){1,7}:|:([0-9a-fA-F]{1,4}:){1,6}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,6}:([0-9a-fA-F]{1,4}:){1,6}[0-9a-fA-F]{1,4})\]:\d+$/;
|
||||
|
||||
// 域名格式:example.com:8080
|
||||
const domainPattern = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*:\d+$/;
|
||||
|
||||
// 更完整的IPv6正则(支持各种压缩格式)
|
||||
const ipv6FullPattern = /^\[((([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4}|:))|(([0-9a-fA-F]{1,4}:){6}(:[0-9a-fA-F]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-fA-F]{1,4}:){5}(((:[0-9a-fA-F]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-fA-F]{1,4}:){4}(((:[0-9a-fA-F]{1,4}){1,3})|((:[0-9a-fA-F]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-fA-F]{1,4}:){3}(((:[0-9a-fA-F]{1,4}){1,4})|((:[0-9a-fA-F]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-fA-F]{1,4}:){2}(((:[0-9a-fA-F]{1,4}){1,5})|((:[0-9a-fA-F]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-fA-F]{1,4}:){1}(((:[0-9a-fA-F]{1,4}){1,6})|((:[0-9a-fA-F]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-fA-F]{1,4}){1,7})|((:[0-9a-fA-F]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))\]:\d+$/;
|
||||
|
||||
if (ipv4Pattern.test(value) || ipv6FullPattern.test(value) || domainPattern.test(value)) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error('请输入正确的地址格式,如: 192.168.1.100:8080 或 [2001:db8::1]:8080 或 example.com:8080'));
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
<el-form-item v-if="isEdit" label="节点IP" prop="ip">
|
||||
<el-input
|
||||
v-model="nodeForm.ip"
|
||||
placeholder="请输入节点IP地址"
|
||||
placeholder="请输入节点IP地址,如: 192.168.1.1 或 2001:db8::1"
|
||||
clearable
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
@@ -312,13 +312,14 @@ export default {
|
||||
if (value) {
|
||||
// IPv4格式验证
|
||||
const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||
// IPv6格式验证(简化版)
|
||||
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^::$/;
|
||||
|
||||
if (!ipv4Regex.test(value) && !ipv6Regex.test(value)) {
|
||||
callback(new Error('请输入有效的IP地址(支持IPv4和IPv6)'));
|
||||
} else {
|
||||
// IPv6格式验证(完整版,支持各种压缩格式)
|
||||
const ipv6Regex = /^((([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4}|:))|(([0-9a-fA-F]{1,4}:){6}(:[0-9a-fA-F]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-fA-F]{1,4}:){5}(((:[0-9a-fA-F]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-fA-F]{1,4}:){4}(((:[0-9a-fA-F]{1,4}){1,3})|((:[0-9a-fA-F]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-fA-F]{1,4}:){3}(((:[0-9a-fA-F]{1,4}){1,4})|((:[0-9a-fA-F]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-fA-F]{1,4}:){2}(((:[0-9a-fA-F]{1,4}){1,5})|((:[0-9a-fA-F]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-fA-F]{1,4}:){1}(((:[0-9a-fA-F]{1,4}){1,6})|((:[0-9a-fA-F]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-fA-F]{1,4}){1,7})|((:[0-9a-fA-F]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/;
|
||||
|
||||
if (ipv4Regex.test(value) || ipv6Regex.test(value)) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error('请输入有效的IP地址(支持IPv4和IPv6格式,如: 192.168.1.1 或 2001:db8::1)'));
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
|
||||
Reference in New Issue
Block a user