Merge pull request #27 from EzLittleChen/dev

fix(api): 修改websocket请求地址, 修改请求方式采用fetch处理
This commit is contained in:
Dawn
2024-10-26 15:12:54 +08:00
committed by GitHub
5 changed files with 291 additions and 11 deletions

View File

@@ -1,7 +1,7 @@
# 后端服务地址
VITE_SERVICE_URL="http://127.0.0.1:9190"
VITE_SERVICE_URL="https://hulaspark.com"
# websocket服务地址
VITE_WEBSOCKET_URL="ws://127.0.0.1:8090"
VITE_WEBSOCKET_URL="wss://hulaspark.com"
# 项目标题
VITE_APP_TITLE="HuLa—IM"
# 项目名称

View File

@@ -1,8 +1,8 @@
import { createAxios } from '@/services/request'
// import { createAxios } from '@/services/request'
import urls from '@/services/urls'
import type {
Response,
BadgeType,
// BadgeType,
CacheBadgeItem,
CacheBadgeReq,
CacheUserItem,
@@ -22,12 +22,18 @@ import type {
UserItem
} from '@/services/types'
const request = createAxios()
// const request = createAxios()
import request from '@/services/request'
const GET = <T>(url: string, params?: any) => request.get<T, Response>(url, params)
const POST = <T>(url: string, params?: any) => request.post<T, Response>(url, params)
const PUT = <T>(url: string, params?: any) => request.put<T, Response>(url, params)
const DELETE = <T>(url: string, params?: any) => request.delete<T, Response>(url, params)
// const GET = <T>(url: string, params?: any) => request.get<T, Response>(url, params)
// const POST = <T>(url: string, params?: any) => request.post<T, Response>(url, params)
// const PUT = <T>(url: string, params?: any) => request.put<T, Response>(url, params)
// const DELETE = <T>(url: string, params?: any) => request.delete<T, Response>(url, params)
const GET = <T>(url: string, params?: any) => request.get<T>(url, params)
const POST = <T>(url: string, params?: any) => request.post<T>(url, params)
const PUT = <T>(url: string, params?: any) => request.put<T>(url, params)
const DELETE = <T>(url: string, params?: any) => request.delete<T>(url, params)
export default {
/** 获取用户信息 */
@@ -52,7 +58,7 @@ export default {
/** 获取用户详细信息 */
getUserDetail: () => GET<UserInfoType>(urls.getUserInfoDetail, {}),
/** 获取徽章列表 */
getBadgeList: (): Promise<Response> => GET<BadgeType[]>(urls.getBadgeList),
getBadgeList: (): Promise<Response> => GET(urls.getBadgeList),
/** 设置用户勋章 */
setUserBadge: (badgeId: number) => PUT<void>(urls.setUserBadge, { badgeId }),
/** 修改用户名 */

159
src/services/http.ts Normal file
View File

@@ -0,0 +1,159 @@
import { fetch } from '@tauri-apps/plugin-http'
/**
* @description 请求参数
* @since Beta v0.5.1
* @property {"GET"|"POST"|"PUT"|"DELETE"} method 请求方法
* @property {Record<string, string>} [headers] 请求头
* @property {Record<string, any>} [query] 请求参数
* @property {any} [body] 请求体
* @property {boolean} [isBlob] 是否为Blob
* @return HttpParams
*/
export type HttpParams = {
method: 'GET' | 'POST' | 'PUT' | 'DELETE'
headers?: Record<string, string>
query?: Record<string, any>
body?: any
isBlob?: boolean
}
/**
* @description HTTP 请求实现
* @since Beta v0.5.1
* @template T
* @param {string} url 请求地址
* @param {HttpParams} options 请求参数
* @param {boolean} [fullResponse=false] 是否返回完整响应
* @returns {Promise<T | { data: Promise<T>; resp: Response }>} 请求结果
*/
async function Http<T>(
url: string,
options: HttpParams,
fullResponse?: true
): Promise<{ data: Promise<T>; resp: Response }> {
// 构建请求头
const httpHeaders = new Headers(options.headers || {})
// 构建 fetch 请求选项
const fetchOptions: RequestInit = {
method: options.method,
headers: httpHeaders
}
// 判断是否需要添加请求体
if (options.body) {
if (!(options.body instanceof FormData || options.body instanceof URLSearchParams)) {
fetchOptions.body = JSON.stringify(options.body)
} else {
fetchOptions.body = options.body // 如果是 FormData 或 URLSearchParams 直接使用
}
}
// 添加查询参数
if (options.query) {
const queryString = new URLSearchParams(options.query).toString()
url += `?${queryString}`
}
// 拼接 API 基础路径
url = `${import.meta.env.VITE_SERVICE_URL}${url}`
console.log('fetch url: ', url)
console.log('fetch options: ', fetchOptions)
try {
const res = await fetch(url, fetchOptions)
if (!res.ok) {
throw new Error(`HTTP error! status: ${res.status}`)
}
const data = options.isBlob ? res.arrayBuffer() : res.json()
if (fullResponse) {
return { data, resp: res }
}
return data
} catch (err) {
console.error('HTTP request failed: ', err)
throw err // 继续抛出错误以便调用方处理
}
}
export default Http
// import { fetch } from '@tauri-apps/plugin-http';
// import * as qs from 'qs';
// const isAbsoluteURL = (url: string) => {
// return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
// };
// const combineURLs = (baseURL: string, relativeURL: string) => {
// return relativeURL
// ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
// : baseURL;
// };
// const buildFullPath = (baseURL: string, requestedURL: string) => {
// if (baseURL && !isAbsoluteURL(requestedURL)) {
// return combineURLs(baseURL, requestedURL);
// }
// return requestedURL;
// };
// const buildURL = (url: string | string[], params: any) => {
// if (!params) {
// return url;
// }
// const serializedParams = qs.stringify(params);
// if (serializedParams) {
// url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
// }
// return url;
// };
// const server = '';
// const baseURL = `${server}/api/`;
// const BODY_TYPE = {
// Form: 'Form',
// Json: 'Json',
// Text: 'Text',
// Bytes: 'Bytes',
// };
// const commonOptions = {
// timeout: 60,
// };
// const http = (url: string, options: any = {}) => {
// const params = { ...options.params };
// if (!options.headers) options.headers = {};
// // todo 可以往 headers 中添加 token 或 cookie 等信息
// if (options?.body) {
// if (options.body.type === BODY_TYPE.Form) {
// options.headers['Content-Type'] = 'multipart/form-data';
// }
// }
// options = { ...commonOptions, ...options };
// let fetchUrl:string = buildFullPath(baseURL, url)
// return fetch(<string>buildURL(fetchUrl, params), options)
// .then((res: any) => {
// const { status, data } = res
// if (status >= 200 && status < 400) {
// return { data };
// }
// return Promise.reject({ status, data });
// })
// .catch((err) => {
// console.error(err);
// return Promise.reject(err);
// });
// };
// export default http;

View File

@@ -1,5 +1,6 @@
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import { useSettingStore } from '@/stores/setting.ts'
import Http, { HttpParams } from './http.ts'
/** 是否是测试环境 */
const isTest = computed(() => {
@@ -141,3 +142,117 @@ export const createAxios = (config?: AxiosRequestConfig): AxiosInstance => {
return instance
}
// fetch 请求响应拦截器
const responseInterceptor = async <T>(
url: string,
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
query: any,
body: any
): Promise<T> => {
const token = useSettingStore().login.accountInfo.token
const headers = {
'Content-Type': 'application/json;charset=utf-8',
Authorization: `Bearer ${token}`
}
let httpParams: HttpParams = {
method,
headers
}
if (method === 'GET') {
httpParams = {
...httpParams,
query
}
} else {
url = `${url}?${new URLSearchParams(query).toString()}`
httpParams = {
...httpParams,
body
}
}
try {
const data = await Http(url, httpParams, true)
const resp = data.resp
if (resp.status > 400) {
let message = ''
switch (resp.status) {
case 400:
message = '错误请求'
break
case 401:
message = '未授权,请重新登录'
break
case 403:
message = '拒绝访问'
break
case 404:
message = '请求错误,未找到该资源'
window.location.href = '/NotFound'
break
case 405:
message = '请求方法未允许'
break
case 408:
message = '请求超时'
break
case 500:
message = '服务器端出错'
break
case 501:
message = '网络未实现'
break
case 502:
message = '网络错误'
break
case 503:
message = '服务不可用'
break
case 504:
message = '网络超时'
break
case 505:
message = 'http版本不支持该请求'
break
default:
message = '连接错误'
}
return Promise.reject(`err: ${message}, status: ${resp.status}`)
}
const res: any = await data.data
return Promise.resolve(res)
} catch (err) {
return Promise.reject(`http error: ${err}`)
}
}
const get = async <T>(url: string, query: T): Promise<T> => {
return responseInterceptor(url, 'GET', query, {})
}
const post = async <T>(url: string, params: any): Promise<T> => {
return responseInterceptor(url, 'POST', {}, params)
}
const put = async <T>(url: string, params: any): Promise<T> => {
return responseInterceptor(url, 'PUT', {}, params)
}
const del = async <T>(url: string, params: any): Promise<T> => {
return responseInterceptor(url, 'DELETE', {}, params)
}
export default {
get,
post,
put,
delete: del
}

View File

@@ -102,7 +102,7 @@ const initConnection = () => {
connection?.removeEventListener('error', onConnectError)
// 建立链接
// 本地配置到 .env 里面修改。生产配置在 .env.production 里面
connection = new WebSocket(`${import.meta.env.VITE_WEBSOCKET_URL}${token ? `?token=${token}` : ''}`)
connection = new WebSocket(`${import.meta.env.VITE_WEBSOCKET_URL}/websocket${token ? `?token=${token}` : ''}`)
// 收到消息
connection.addEventListener('message', onConnectMsg)
// 建立链接