fix: AI服务改用HttpsURLConnection解决SSL兼容问题+超时5分钟+超时直接提示失败
This commit is contained in:
1 parent
325c22fd09
commit
a0ac75ebca
2 files changed
+80
-48
No files matched your search
@@ -9,11 +9,15 @@ import xuan.config.AiProperties;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.cert.X509Certificate;
|
||||
@@ -33,27 +37,11 @@ public class AiService {
|
||||
}
|
||||
|
||||
private OkHttpClient buildClient() {
|
||||
try {
|
||||
TrustManager[] trustManagers = new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
|
||||
}
|
||||
};
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, trustManagers, null);
|
||||
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
||||
return new OkHttpClient.Builder()
|
||||
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagers[0])
|
||||
.hostnameVerifier((hostname, session) -> true)
|
||||
.connectTimeout(properties.getConnectTimeout(), TimeUnit.SECONDS)
|
||||
.readTimeout(properties.getReadTimeout(), TimeUnit.SECONDS)
|
||||
.writeTimeout(properties.getConnectTimeout(), TimeUnit.SECONDS)
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to build OkHttpClient", e);
|
||||
}
|
||||
return new OkHttpClient.Builder()
|
||||
.connectTimeout(properties.getConnectTimeout(), TimeUnit.SECONDS)
|
||||
.readTimeout(properties.getReadTimeout(), TimeUnit.SECONDS)
|
||||
.writeTimeout(properties.getConnectTimeout(), TimeUnit.SECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
public String chat(String systemPrompt, String userMessage) {
|
||||
@@ -72,7 +60,7 @@ public class AiService {
|
||||
|
||||
try {
|
||||
String baseUrl = properties.getBaseUrl().replaceAll("/+$", "");
|
||||
String url = baseUrl + "/v1/chat/completions";
|
||||
String urlStr = baseUrl + "/v1/chat/completions";
|
||||
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("model", properties.getModel());
|
||||
@@ -95,20 +83,47 @@ public class AiService {
|
||||
|
||||
String payload = requestBody.toJSONString();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(RequestBody.create(payload, MediaType.parse("application/json; charset=utf-8")))
|
||||
.addHeader("Authorization", "Bearer " + apiKey)
|
||||
.addHeader("Content-Type", "application/json; charset=utf-8")
|
||||
.build();
|
||||
URL url = new URL(urlStr);
|
||||
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setDoOutput(true);
|
||||
conn.setConnectTimeout(properties.getConnectTimeout() * 1000);
|
||||
conn.setReadTimeout(properties.getReadTimeout() * 1000);
|
||||
conn.setRequestProperty("Authorization", "Bearer " + apiKey);
|
||||
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
String responseBody = response.body() != null ? response.body().string() : "";
|
||||
if (!response.isSuccessful()) {
|
||||
return "AI服务请求失败(HTTP " + response.code() + "):" + responseBody;
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
|
||||
}
|
||||
return parseOpenAIResponse(responseBody);
|
||||
}, null);
|
||||
conn.setSSLSocketFactory(sslContext.getSocketFactory());
|
||||
conn.setHostnameVerifier((hostname, session) -> true);
|
||||
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
os.write(payload.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
try (BufferedReader br = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
responseCode >= 200 && responseCode < 300
|
||||
? conn.getInputStream() : conn.getErrorStream(),
|
||||
StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
responseBody.append(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (responseCode < 200 || responseCode >= 300) {
|
||||
return "AI服务请求失败(HTTP " + responseCode + "):" + responseBody;
|
||||
}
|
||||
return parseOpenAIResponse(responseBody.toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "AI分析暂时不可用,请稍后再试。错误信息:" + e.getMessage();
|
||||
@@ -123,7 +138,14 @@ public class AiService {
|
||||
JSONObject choice = choices.getJSONObject(0);
|
||||
JSONObject message = choice.getJSONObject("message");
|
||||
if (message != null) {
|
||||
return message.getString("content");
|
||||
String content = message.getString("content");
|
||||
if (content != null && content.startsWith("<think")) {
|
||||
int endIdx = content.indexOf("</think");
|
||||
if (endIdx != -1) {
|
||||
content = content.substring(endIdx + 8).trim();
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return "AI未返回有效内容";
|
||||
|
||||
@@ -10,6 +10,13 @@ const request = (options, retryCount = 0) => {
|
||||
})
|
||||
}
|
||||
|
||||
let slowTimer = setTimeout(() => {
|
||||
uni.showLoading({
|
||||
title: '测算时间有点长,请耐心等待...',
|
||||
mask: true
|
||||
})
|
||||
}, 30000)
|
||||
|
||||
uni.request({
|
||||
url: BASE_URL + options.url,
|
||||
method: options.method || 'GET',
|
||||
@@ -18,12 +25,11 @@ const request = (options, retryCount = 0) => {
|
||||
'Content-Type': 'application/json',
|
||||
...options.header
|
||||
},
|
||||
timeout: 60000,
|
||||
timeout: 300000,
|
||||
success: (res) => {
|
||||
clearTimeout(slowTimer)
|
||||
uni.hideLoading()
|
||||
if (res.statusCode === 200) {
|
||||
if (retryCount > 0) {
|
||||
uni.hideLoading()
|
||||
}
|
||||
resolve(res.data)
|
||||
} else if (res.statusCode >= 500 && retryCount < MAX_RETRY) {
|
||||
retryCount++
|
||||
@@ -35,25 +41,31 @@ const request = (options, retryCount = 0) => {
|
||||
request(options, retryCount).then(resolve).catch(reject)
|
||||
}, 2000)
|
||||
} else {
|
||||
if (retryCount > 0) {
|
||||
uni.hideLoading()
|
||||
}
|
||||
reject(new Error('网络请求失败: ' + res.statusCode))
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
clearTimeout(slowTimer)
|
||||
uni.hideLoading()
|
||||
const isTimeout = err.errMsg && (err.errMsg.indexOf('timeout') !== -1 || err.errMsg.indexOf('超时') !== -1)
|
||||
if (isTimeout && retryCount < MAX_RETRY) {
|
||||
if (isTimeout) {
|
||||
uni.showModal({
|
||||
title: '测算失败',
|
||||
content: 'AI分析超时,请稍后再试',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
})
|
||||
reject(new Error('测算超时'))
|
||||
} else if (retryCount < MAX_RETRY) {
|
||||
retryCount++
|
||||
uni.showLoading({
|
||||
title: '请求超时,重试中(' + retryCount + '/' + MAX_RETRY + ')...',
|
||||
title: '重新连接中(' + retryCount + '/' + MAX_RETRY + ')...',
|
||||
mask: true
|
||||
})
|
||||
setTimeout(() => {
|
||||
request(options, retryCount).then(resolve).catch(reject)
|
||||
}, 2000)
|
||||
} else if (retryCount >= MAX_RETRY) {
|
||||
uni.hideLoading()
|
||||
} else {
|
||||
uni.showModal({
|
||||
title: '请求失败',
|
||||
content: '已重试' + MAX_RETRY + '次仍无法连接服务器,请检查网络后重试',
|
||||
@@ -61,8 +73,6 @@ const request = (options, retryCount = 0) => {
|
||||
confirmText: '知道了'
|
||||
})
|
||||
reject(new Error('重试' + MAX_RETRY + '次后仍失败:' + (err.errMsg || '网络连接失败')))
|
||||
} else {
|
||||
reject(new Error(err.errMsg || '网络连接失败'))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user