抛出异常的处理
parent
2709171839
commit
3bea7ab015
|
|
@ -20,12 +20,16 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class OmsClient {
|
||||
|
||||
private static final Set<String> SUCCESS_CODES = Set.of("0", "200", "success", "SUCCESS");
|
||||
private static final Pattern HTML_TITLE_PATTERN = Pattern.compile("<title[^>]*>(.*?)</title>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
|
||||
private static final Pattern HTML_HEADING_PATTERN = Pattern.compile("<h[1-6][^>]*>(.*?)</h[1-6]>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
|
||||
private static final List<String> PROJECT_CODE_FIELDS = List.of(
|
||||
"project_code",
|
||||
"projectCode",
|
||||
|
|
@ -207,16 +211,22 @@ public class OmsClient {
|
|||
private JsonNode sendRequest(HttpRequest request) {
|
||||
try {
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
String responseBody = response.body();
|
||||
String contentType = response.headers().firstValue("Content-Type").orElse(null);
|
||||
if (response.statusCode() < 200 || response.statusCode() >= 300) {
|
||||
throw new BusinessException("OMS接口调用失败,HTTP状态码: " + response.statusCode() + ",响应: " + trimBody(response.body()));
|
||||
throw new BusinessException(resolveOmsResponseMessage(response.statusCode(), responseBody, contentType));
|
||||
}
|
||||
JsonNode root = objectMapper.readTree(response.body());
|
||||
if (!looksLikeJson(contentType, responseBody)) {
|
||||
throw new BusinessException(resolveOmsResponseMessage(response.statusCode(), responseBody, contentType));
|
||||
}
|
||||
|
||||
JsonNode root = objectMapper.readTree(responseBody);
|
||||
String code = normalizeText(root.path("code").asText(null));
|
||||
if (!isSuccessCode(code)) {
|
||||
String message = firstNonBlank(
|
||||
normalizeText(root.path("msg").asText(null)),
|
||||
normalizeText(root.path("message").asText(null)),
|
||||
trimBody(response.body()),
|
||||
trimBody(responseBody),
|
||||
"OMS接口调用失败");
|
||||
throw new BusinessException(message);
|
||||
}
|
||||
|
|
@ -229,6 +239,74 @@ public class OmsClient {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean looksLikeJson(String contentType, String body) {
|
||||
String normalizedContentType = normalizeText(contentType);
|
||||
if (normalizedContentType != null) {
|
||||
String lowerCaseContentType = normalizedContentType.toLowerCase(Locale.ROOT);
|
||||
if (lowerCaseContentType.contains("application/json") || lowerCaseContentType.contains("+json")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String normalizedBody = normalizeText(body);
|
||||
return normalizedBody != null && (normalizedBody.startsWith("{") || normalizedBody.startsWith("["));
|
||||
}
|
||||
|
||||
private String resolveOmsResponseMessage(int statusCode, String body, String contentType) {
|
||||
String visibleMessage = firstNonBlank(
|
||||
extractHtmlErrorMessage(body),
|
||||
trimBody(body));
|
||||
if (!isBlank(visibleMessage)) {
|
||||
return visibleMessage;
|
||||
}
|
||||
|
||||
String normalizedContentType = normalizeText(contentType);
|
||||
if (!isBlank(normalizedContentType)) {
|
||||
return "OMS接口调用失败,HTTP状态码: " + statusCode + ",响应类型: " + normalizedContentType;
|
||||
}
|
||||
return "OMS接口调用失败,HTTP状态码: " + statusCode;
|
||||
}
|
||||
|
||||
private String extractHtmlErrorMessage(String body) {
|
||||
String normalizedBody = normalizeText(body);
|
||||
if (normalizedBody == null || !normalizedBody.startsWith("<")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String heading = extractHtmlFragment(normalizedBody, HTML_HEADING_PATTERN);
|
||||
String title = extractHtmlFragment(normalizedBody, HTML_TITLE_PATTERN);
|
||||
String textOnly = normalizeText(
|
||||
normalizedBody
|
||||
.replaceAll("(?is)<script[^>]*>.*?</script>", " ")
|
||||
.replaceAll("(?is)<style[^>]*>.*?</style>", " ")
|
||||
.replaceAll("(?is)<[^>]+>", " ")
|
||||
.replace(" ", " ")
|
||||
.replaceAll("\\s+", " "));
|
||||
|
||||
if (!isBlank(heading)) {
|
||||
return heading;
|
||||
}
|
||||
if (!isBlank(textOnly)) {
|
||||
if (!isBlank(title) && !textOnly.startsWith(title)) {
|
||||
return (title + " " + textOnly).trim();
|
||||
}
|
||||
return textOnly;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
private String extractHtmlFragment(String body, Pattern pattern) {
|
||||
Matcher matcher = pattern.matcher(body);
|
||||
if (!matcher.find()) {
|
||||
return null;
|
||||
}
|
||||
String content = matcher.group(1);
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
return normalizeText(content.replaceAll("(?is)<[^>]+>", " ").replaceAll("\\s+", " "));
|
||||
}
|
||||
|
||||
private URI buildUri(String path, Map<String, String> queryParams) {
|
||||
validateConfigured();
|
||||
String baseUrl = normalizeBaseUrl(omsProperties.getBaseUrl());
|
||||
|
|
|
|||
|
|
@ -650,6 +650,64 @@ function handleUnauthorizedResponse() {
|
|||
window.location.href = `${LOGIN_PATH}?timeout=1`;
|
||||
}
|
||||
|
||||
function tryParseApiBody<T>(rawText: string, contentType?: string | null): (ApiEnvelope<T> & ApiErrorBody) | null {
|
||||
const normalizedText = rawText.trim();
|
||||
const normalizedContentType = (contentType || "").toLowerCase();
|
||||
const looksLikeJson = normalizedContentType.includes("application/json")
|
||||
|| normalizedContentType.includes("+json")
|
||||
|| normalizedText.startsWith("{")
|
||||
|| normalizedText.startsWith("[");
|
||||
|
||||
if (!normalizedText || !looksLikeJson) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(normalizedText) as ApiEnvelope<T> & ApiErrorBody;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function extractHtmlErrorMessage(rawText: string) {
|
||||
const titleMatch = rawText.match(/<title[^>]*>([^<]+)<\/title>/i);
|
||||
if (titleMatch?.[1]?.trim()) {
|
||||
return titleMatch[1].trim();
|
||||
}
|
||||
|
||||
const headingMatch = rawText.match(/<h[1-6][^>]*>([^<]+)<\/h[1-6]>/i);
|
||||
if (headingMatch?.[1]?.trim()) {
|
||||
return headingMatch[1].trim();
|
||||
}
|
||||
|
||||
const textOnly = rawText
|
||||
.replace(/<script[\s\S]*?<\/script>/gi, " ")
|
||||
.replace(/<style[\s\S]*?<\/style>/gi, " ")
|
||||
.replace(/<[^>]+>/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
|
||||
return textOnly || null;
|
||||
}
|
||||
|
||||
function buildApiErrorMessage(rawText: string, status: number, body?: ApiErrorBody | null) {
|
||||
const directMessage = body?.msg?.trim() || body?.message?.trim();
|
||||
if (directMessage) {
|
||||
return directMessage;
|
||||
}
|
||||
|
||||
const normalizedText = rawText.trim();
|
||||
if (!normalizedText) {
|
||||
return `请求失败(${status})`;
|
||||
}
|
||||
|
||||
if (normalizedText.startsWith("<")) {
|
||||
return extractHtmlErrorMessage(normalizedText) || `请求失败(${status})`;
|
||||
}
|
||||
|
||||
return normalizedText.length > 300 ? normalizedText.slice(0, 300) : normalizedText;
|
||||
}
|
||||
|
||||
async function request<T>(input: string, init?: RequestInit, withAuth = false): Promise<T> {
|
||||
const headers = new Headers(init?.headers);
|
||||
if (!headers.has("Content-Type") && init?.body && !(init.body instanceof FormData)) {
|
||||
|
|
@ -670,25 +728,19 @@ async function request<T>(input: string, init?: RequestInit, withAuth = false):
|
|||
throw new Error("登录已失效,请重新登录");
|
||||
}
|
||||
|
||||
let body: (ApiEnvelope<T> & ApiErrorBody) | null = null;
|
||||
try {
|
||||
body = (await response.json()) as ApiEnvelope<T> & ApiErrorBody;
|
||||
} catch {
|
||||
if (!response.ok) {
|
||||
throw new Error(`请求失败(${response.status})`);
|
||||
}
|
||||
}
|
||||
const rawText = await response.text();
|
||||
const body = tryParseApiBody<T>(rawText, response.headers.get("content-type"));
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(body?.msg || body?.message || `请求失败(${response.status})`);
|
||||
throw new Error(buildApiErrorMessage(rawText, response.status, body));
|
||||
}
|
||||
|
||||
if (!body) {
|
||||
throw new Error("接口返回为空");
|
||||
throw new Error(rawText.trim() ? buildApiErrorMessage(rawText, response.status, null) : "接口返回为空");
|
||||
}
|
||||
|
||||
if (body.code !== "0") {
|
||||
throw new Error(body.msg || "请求失败");
|
||||
throw new Error(buildApiErrorMessage(rawText, response.status, body));
|
||||
}
|
||||
|
||||
return body.data;
|
||||
|
|
|
|||
Loading…
Reference in New Issue