链接上数据库
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
// /components/supadb/aksupa.uts
|
||||
import { AkReqResponse, AkReqUploadOptions, AkReq } from '@/uni_modules/ak-req/index.uts'
|
||||
import type { AkReqOptions } from '@/uni_modules/ak-req/index.uts'
|
||||
import { toUniError } from '@/utils/utils.uts'
|
||||
import { IS_TEST_MODE } from '@/ak/config.uts'
|
||||
|
||||
export type AkSupaSignInResult = {
|
||||
access_token : string;
|
||||
@@ -805,14 +807,22 @@ export class AkSupa {
|
||||
* { usr_id: { lt: 800 }, name: { ilike: '%foo%' }, status: 'active', age: { gte: 18, lte: 30 } }
|
||||
* 操作符支持 eq, neq, lt, lte, gt, gte, like, ilike, in, is, not, contains, containedBy, range, fts, plfts, phfts, wfts
|
||||
*/
|
||||
async select(table : string, filter ?: string | null, options ?: AkSupaSelectOptions) : Promise<AkReqResponse<any>> {
|
||||
let url = this.baseUrl + '/rest/v1/' + table;
|
||||
let headers = {
|
||||
apikey: this.apikey,
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${AkReq.getToken() ?? ''}`
|
||||
} as UTSJSONObject;
|
||||
let params : string[] = [];
|
||||
async select(table : string, filter ?: string | null, options ?: AkSupaSelectOptions) : Promise<AkReqResponse<any>> {
|
||||
let url = this.baseUrl + '/rest/v1/' + table;
|
||||
|
||||
const token = AkReq.getToken()
|
||||
let headers = {
|
||||
apikey: this.apikey,
|
||||
'Content-Type': 'application/json'
|
||||
} as UTSJSONObject;
|
||||
|
||||
// 只有在明确有用户 token 的情况下才发送 Authorization
|
||||
// 否则只带 apikey,这样 Kong 会自动映射到 anon 角色,避免 JWT 校验失败
|
||||
if (token != null && token != '') {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
let params : string[] = [];
|
||||
if (options != null) {
|
||||
if (options.columns != null && !(options.columns == "")) params.push('select=' + encodeURIComponent(options.columns ?? ""));
|
||||
if (options.limit != null) {
|
||||
@@ -897,10 +907,17 @@ async select_uts(table : string, filter ?: UTSJSONObject | null, options ?: AkSu
|
||||
*/
|
||||
async insert(table : string, row : UTSJSONObject | Array<UTSJSONObject>) : Promise<AkReqResponse<any>> {
|
||||
const url = this.baseUrl + '/rest/v1/' + table;
|
||||
const headers = {
|
||||
|
||||
const token = AkReq.getToken()
|
||||
let authHeader = `Bearer ${this.apikey}`;
|
||||
if (token != null && token != '') {
|
||||
authHeader = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
let headers = {
|
||||
apikey: this.apikey,
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${AkReq.getToken() ?? ''}`,
|
||||
Authorization: authHeader,
|
||||
Prefer: 'return=representation'
|
||||
} as UTSJSONObject;
|
||||
|
||||
@@ -910,7 +927,7 @@ async select_uts(table : string, filter ?: UTSJSONObject | null, options ?: AkSu
|
||||
url,
|
||||
method: 'POST',
|
||||
headers,
|
||||
data: row, // 可以是单个对象或数组
|
||||
data: row,
|
||||
contentType: 'application/json'
|
||||
};
|
||||
return await this.requestWithAutoRefresh(reqOptions);
|
||||
@@ -928,12 +945,18 @@ async update(table : string, filter : string | null, values : UTSJSONObject) : P
|
||||
if (filter!=null && filter !== "") {
|
||||
url += '?' + filter;
|
||||
}
|
||||
const headers = {
|
||||
|
||||
const token = AkReq.getToken()
|
||||
let headers = {
|
||||
apikey: this.apikey,
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${AkReq.getToken() ?? ''}`,
|
||||
Prefer: 'return=representation'
|
||||
} as UTSJSONObject;
|
||||
|
||||
if (token != null && token != '') {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
let reqOptions : AkReqOptions = {
|
||||
url,
|
||||
method: 'PATCH',
|
||||
@@ -955,12 +978,18 @@ async delete(table : string, filter : string | null) : Promise<AkReqResponse<any
|
||||
if (filter!=null && filter !== "") {
|
||||
url += '?' + filter;
|
||||
}
|
||||
const headers = {
|
||||
|
||||
const token = AkReq.getToken()
|
||||
let headers = {
|
||||
apikey: this.apikey,
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${AkReq.getToken() ?? ''}`,
|
||||
Prefer: 'return=representation'
|
||||
} as UTSJSONObject;
|
||||
|
||||
if (token != null && token != '') {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
let reqOptions : AkReqOptions = {
|
||||
url,
|
||||
method: 'DELETE',
|
||||
@@ -978,11 +1007,17 @@ async delete(table : string, filter : string | null) : Promise<AkReqResponse<any
|
||||
*/
|
||||
async rpc(functionName : string, params ?: UTSJSONObject) : Promise<AkReqResponse<any>> {
|
||||
const url = `${this.baseUrl}/rest/v1/rpc/${functionName}`;
|
||||
const headers = {
|
||||
|
||||
const token = AkReq.getToken()
|
||||
let headers = {
|
||||
apikey: this.apikey,
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${AkReq.getToken() ?? ''}`
|
||||
'Content-Type': 'application/json'
|
||||
} as UTSJSONObject;
|
||||
|
||||
if (token != null && token != '') {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
let reqOptions : AkReqOptions = {
|
||||
url,
|
||||
method: 'POST',
|
||||
@@ -1042,24 +1077,34 @@ async delete(table : string, filter : string | null) : Promise<AkReqResponse<any
|
||||
// AkSupa类内新增:自动刷新封装
|
||||
async requestWithAutoRefresh(reqOptions : AkReqOptions, isRetry = false) : Promise<AkReqResponse<any>> {
|
||||
let res = await AkReq.request(reqOptions, false);
|
||||
// JWT过期:Supabase风格
|
||||
const isJwtExpired = (res.status == 401); //res != null && res.data != null && typeof res.data == 'object' && (res.data as UTSJSONObject)?.getString('code') == 'PGRST301';
|
||||
// 401未授权
|
||||
const isUnauthorized = (res.status == 401);
|
||||
if ((isJwtExpired || isUnauthorized) && !isRetry) {
|
||||
// JWT过期/401未授权
|
||||
const needsHandle = (res.status == 401);
|
||||
|
||||
if (needsHandle && !isRetry) {
|
||||
const ok = await this.refreshSession();
|
||||
if (ok) {
|
||||
const newToken = AkReq.getToken() ?? ''
|
||||
let headers = reqOptions.headers
|
||||
if (headers == null) {
|
||||
headers = new UTSJSONObject()
|
||||
}
|
||||
if (typeof headers.set == 'function') {
|
||||
headers.set('Authorization', `Bearer ${AkReq.getToken() ?? ''}`)
|
||||
headers.set('Authorization', `Bearer ${newToken}`)
|
||||
reqOptions.headers = headers
|
||||
}
|
||||
|
||||
res = await AkReq.request(reqOptions, false);
|
||||
} else {
|
||||
// 如果是测试模式且失败(401且无法刷新),不再抛出异常阻止执行,但确保 res.error 有值
|
||||
if (IS_TEST_MODE === true) {
|
||||
console.warn('[TestMode] Token expired or not found, but continuing anyway. Status:', res.status)
|
||||
console.log('[TestMode] Response body:', JSON.stringify(res.data))
|
||||
if (res.error == null) {
|
||||
res.error = toUniError('认证失败 (401)', 'UNAUTHORIZED');
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
uni.removeStorageSync('user_id');
|
||||
uni.removeStorageSync('token');
|
||||
|
||||
@@ -1067,6 +1112,12 @@ async delete(table : string, filter : string | null) : Promise<AkReqResponse<any
|
||||
throw toUniError('登录已过期,请重新登录', '用户认证失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 额外检查:如果 status >= 400 且 res.error 为空,注入一个 error
|
||||
if (res.status >= 400 && res.error == null) {
|
||||
res.error = toUniError(`请求失败: ${res.status}`, 'HTTP_ERROR');
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user