Просмотр исходного кода

fix(network): 修复小程序网络请求失败问题

- 抽离可配置 BASE_URL,默认使用正确后端端口 8080
- 支持 VITE_APP_BASE_URL 环境变量覆盖,便于真机调试
- 新增 20 秒请求超时
- 优化错误提示,区分超时/CORS/无响应等场景
zhangzhicheng 1 неделя назад
Родитель
Сommit
ae1aa34bd4
2 измененных файлов с 40 добавлено и 5 удалено
  1. 31 5
      src/api/request.ts
  2. 9 0
      src/config/index.ts

+ 31 - 5
src/api/request.ts

@@ -1,6 +1,5 @@
 // HTTP 请求封装
-
-const BASE_URL = 'http://localhost:8081/api'
+import { BASE_URL, REQUEST_TIMEOUT } from '../config'
 
 interface RequestOptions {
   url: string
@@ -25,6 +24,26 @@ function translateErrorMsg(msg: string): string {
   return msg
 }
 
+function getNetworkErrorMessage(err: any): string {
+  // #ifdef H5
+  if (typeof err === 'object') {
+    // CORS / 预检失败常见表现
+    if (err.status === 0 || err.readyState === 0) {
+      return '无法连接服务器,请检查网络或后端地址配置(CORS/跨域)'
+    }
+  }
+  // #endif
+
+  const errMsg = String(err?.errMsg || err?.message || err || '')
+  if (errMsg.includes('timeout') || errMsg.includes('超时')) {
+    return '请求超时,请稍后重试'
+  }
+  if (errMsg.includes('fail') || errMsg.includes('无法连接') || errMsg.includes('connect')) {
+    return '网络连接失败,请检查网络或服务器地址'
+  }
+  return '网络请求失败,请检查网络'
+}
+
 export async function request<T = any>(options: RequestOptions): Promise<T> {
   const { url, method = 'GET', data, params, header = {}, loading = true } = options
 
@@ -60,6 +79,7 @@ export async function request<T = any>(options: RequestOptions): Promise<T> {
       method,
       data,
       header: requestHeader,
+      timeout: REQUEST_TIMEOUT,
       success: (res) => {
         if (loading) uni.hideLoading()
 
@@ -87,15 +107,21 @@ export async function request<T = any>(options: RequestOptions): Promise<T> {
           uni.removeStorageSync('user')
           uni.reLaunch({ url: '/pages/login/login' })
           reject(new Error('Unauthorized'))
+        } else if (res.statusCode === 0 || res.statusCode === undefined) {
+          // 部分平台网络异常时 statusCode 为 0
+          const msg = getNetworkErrorMessage(res)
+          uni.showToast({ title: msg, icon: 'none' })
+          reject(new Error(msg))
         } else {
-          uni.showToast({ title: `请求失败: ${res.statusCode}`, icon: 'none' })
+          uni.showToast({ title: `请求失败 (${res.statusCode})`, icon: 'none' })
           reject(new Error(`HTTP ${res.statusCode}`))
         }
       },
       fail: (err) => {
         if (loading) uni.hideLoading()
-        uni.showToast({ title: '网络请求失败', icon: 'none' })
-        reject(err)
+        const msg = getNetworkErrorMessage(err)
+        uni.showToast({ title: msg, icon: 'none' })
+        reject(new Error(msg))
       },
     })
   })

+ 9 - 0
src/config/index.ts

@@ -0,0 +1,9 @@
+// 全局配置
+// 开发环境建议配置为后端所在电脑的局域网 IP,例如:http://192.168.1.100:8080/api
+// 真机调试/预览时 localhost 指向手机自身,无法访问电脑后端,必须改为局域网 IP
+// 生产环境通过构建时注入 VITE_APP_BASE_URL 覆盖
+const DEFAULT_BASE_URL = 'http://localhost:8080/api'
+
+export const BASE_URL = import.meta.env.VITE_APP_BASE_URL || DEFAULT_BASE_URL
+
+export const REQUEST_TIMEOUT = 20000