etherreq 1.1.16 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/etherreq.js DELETED
@@ -1,95 +0,0 @@
1
- // src/etherreq.js
2
-
3
- export const create = (defaultConfig = {}) => {
4
- const interceptors = {
5
- request: [],
6
- response: [],
7
- };
8
-
9
- const use = (fulfilled, rejected, type = 'request') => {
10
- interceptors[type].push({ fulfilled, rejected });
11
- };
12
-
13
- // ✅ 使用 const 显式声明 dispatchRequest
14
- // etherreq.js
15
- const dispatchRequest = async (config) => {
16
- // 请求拦截器执行
17
- for (const interceptor of interceptors.request) {
18
- const nextConfig = await interceptor.fulfilled(config);
19
- // ✅ 拦截器可以返回一个 response 对象,表示中断请求
20
- if (nextConfig && nextConfig.isFromCache) {
21
- return nextConfig.data; // ✅ 直接返回缓存结果,不再往下执行
22
- }
23
- config = nextConfig;
24
- }
25
-
26
- let response;
27
- const { url, method = 'GET', headers = {}, body } = config;
28
- let text = '';
29
- try {
30
- const options = {
31
- method,
32
- headers,
33
- body: method !== 'GET' ? JSON.stringify(body) : undefined,
34
- };
35
-
36
- const res = await fetch(url, options);
37
- text = await res.text();
38
- if (!res.ok) {
39
- throw new Error(`HTTP 错误: ${res.status} - ${res.statusText}`);
40
- }
41
-
42
- if (text.trim().startsWith('<')) {
43
- throw new Error('服务器返回了 HTML 页面,预期为 JSON 格式');
44
- }
45
-
46
- const data = JSON.parse(text);
47
-
48
- response = {
49
- data,
50
- status: res.status,
51
- statusText: res.statusText,
52
- headers: res.headers,
53
- config,
54
- };
55
- } catch (error) {
56
- error.message += `\n请求地址: ${url}`;
57
- if (text) {
58
- error.message += `\n响应内容: ${text.substring(0, 200)}...`;
59
- }
60
-
61
- for (const interceptor of interceptors.response) {
62
- if (interceptor.rejected) {
63
- return interceptor.rejected(error);
64
- }
65
- }
66
-
67
- throw error;
68
- }
69
-
70
- // 响应拦截器执行
71
- for (const interceptor of interceptors.response) {
72
- response = await interceptor.fulfilled(response);
73
- }
74
-
75
- return response;
76
- };
77
- const instance = (config) => {
78
- return dispatchRequest({
79
- ...defaultConfig,
80
- ...config,
81
- });
82
- };
83
-
84
- instance.use = (fulfilled, rejected) => use(fulfilled, rejected, 'request');
85
- instance.interceptors = {
86
- request: {
87
- use: (fulfilled, rejected) => use(fulfilled, rejected, 'request'),
88
- },
89
- response: {
90
- use: (fulfilled, rejected) => use(fulfilled, rejected, 'response'),
91
- },
92
- };
93
-
94
- return instance;
95
- };
package/src/index.js DELETED
@@ -1,79 +0,0 @@
1
- // src/index.js
2
- import { request, baseURL as _baseURL, setBaseURL } from './request.js';
3
- // 示例封装方法
4
- const createMethod = (method) => (url, data, callback) => {
5
- let options;
6
- if (
7
- data &&
8
- typeof data === 'object' &&
9
- !Array.isArray(data) &&
10
- !(data instanceof FormData) &&
11
- !data.method &&
12
- !data.headers &&
13
- !data.params &&
14
- !data.baseURL
15
- ) {
16
- options = { body: data, method };
17
- } else {
18
- options = { ...data, method };
19
- }
20
-
21
- const promise = request(url, options);
22
-
23
- if (typeof callback === 'function') {
24
- promise.then(data => callback(null, data)).catch(err => callback(err, null));
25
- } else {
26
- return promise;
27
- }
28
- };
29
-
30
- export const etherreq = Object.assign(
31
- (url, options, callback) => createMethod('GET')(url, options, callback),
32
- {
33
- get: createMethod('GET'),
34
- post: createMethod('POST'),
35
- put: createMethod('PUT'),
36
- delete: createMethod('DELETE'),
37
- del: createMethod('DELETE'),
38
- login: (url, data, callback) => {
39
- const loginPromise = createMethod('POST')(url, data);
40
-
41
- loginPromise.then(response => {
42
- const token = response.data?.token;
43
- if (token) {
44
- localStorage.setItem('token', token); // 保存 token 到 localStorage
45
- }
46
- return response;
47
- });
48
-
49
- if (typeof callback === 'function') {
50
- loginPromise.then(data => callback(null, data)).catch(err => callback(err, null));
51
- } else {
52
- return loginPromise;
53
- }
54
- },
55
- }
56
- );
57
- therreq.install = (app, options = {}) => {
58
- // 合并基础 URL 配置
59
- if (options.baseURL) {
60
- setBaseURL(options.baseURL);
61
- }
62
-
63
- // 兼容 Vue2 和 Vue3 的挂载方式
64
- if (typeof app === 'function' && app.prototype) { // Vue2
65
- app.prototype.$etherreq = etherreq;
66
- } else if (app.config) { // Vue3
67
- app.config.globalProperties.$etherreq = etherreq;
68
- }
69
- };
70
-
71
- // 导出组合式函数(仅 Vue3 可用)
72
- export const useEtherReq = () => {
73
- const instance = getCurrentInstance();
74
- if (!instance) {
75
- throw new Error('useEtherReq 必须在 Vue 组件的 setup 函数中调用');
76
- }
77
- return instance.appContext.config.globalProperties.$etherreq;
78
- };
79
- export { setBaseURL, _baseURL as baseURL };
package/src/request.js DELETED
@@ -1,88 +0,0 @@
1
- // src/request.js
2
- import { create } from './etherreq.js';
3
- import { requestCache, getCacheKey } from './cache.js';
4
-
5
- // 创建一个带有默认配置的请求实例
6
- const instance = create({
7
- baseURL: 'https://api.example.com', // 默认基础 URL
8
- });
9
-
10
- // 请求拦截器
11
- instance.interceptors.request.use((config) => {
12
- const token = localStorage.getItem('token');
13
-
14
- const headers = {
15
- ...(config.headers || {}),
16
- Authorization: token ? `Bearer ${token}` : undefined,
17
- 'Content-Type': 'application/json',
18
- };
19
-
20
- // 新增:若存在幂等令牌,强制启用缓存校验(即使非GET请求)
21
- const useCache = (config.method === 'GET' && !config.disableCache) || !!config.idempotencyKey;
22
- if (useCache) {
23
- const cacheKey = getCacheKey(config.url, config);
24
- const cached = requestCache.get(cacheKey);
25
-
26
- if (cached) {
27
- return Promise.resolve({
28
- data: cached,
29
- status: 200,
30
- statusText: 'OK',
31
- config,
32
- isFromCache: true,
33
- });
34
- }
35
- }
36
-
37
- return {
38
- ...config,
39
- headers,
40
- };
41
- });
42
-
43
- // 响应拦截器
44
- instance.interceptors.response.use(
45
- (response) => {
46
- if (response.isFromCache) {
47
- return response.data;
48
- }
49
-
50
- const config = response.config;
51
- // 新增:若存在幂等令牌或GET请求未禁用缓存,则缓存结果
52
- const shouldCache = !!config.idempotencyKey || (config.method === 'GET' && !config.disableCache);
53
- if (shouldCache) {
54
- const cacheKey = getCacheKey(config.url, config);
55
- requestCache.set(cacheKey, response.data);
56
- }
57
-
58
- return response.data;
59
- },
60
- (error) => {
61
- console.error('请求异常:', error);
62
- return Promise.reject(error);
63
- }
64
- );
65
- let _baseURL = 'https://api..com'; // 内部变量用于保存 base URL
66
-
67
- /**
68
- * 封装 request 函数,支持 baseURl 拼接等逻辑
69
- * @param {string} url - 请求路径
70
- * @param {Object} options - 请求配置
71
- */
72
- export const request = (url, options = {}) => {
73
- const baseURL = options.baseURL || _baseURL;
74
- const finalURL = new URL(url, baseURL).toString();
75
-
76
- return instance({
77
- ...options,
78
- url: finalURL,
79
- });
80
- };
81
-
82
- // 导出可读写的 baseURL 变量
83
- export { _baseURL as baseURL };
84
-
85
- // 允许外部设置 baseURL
86
- export const setBaseURL = (newBaseURL) => {
87
- _baseURL = newBaseURL;
88
- };
@@ -1,50 +0,0 @@
1
- interface EtherRequestOptions {
2
- method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
3
- headers?: Record<string, string | number | boolean>;
4
- body?: any;
5
- params?: Record<string, any>;
6
- baseURL?: string;
7
- idempotencyKey?: string; // 新增:幂等请求令牌
8
- }
9
-
10
- interface EtherRequestResponse<T = any> {
11
- data: T;
12
- status: number;
13
- statusText: string;
14
- headers: Headers;
15
- }
16
-
17
- // 请求方法类型
18
- type EtherRequestMethod = <T = any>(
19
- url: string,
20
- options?: EtherRequestOptions
21
- ) => Promise<T>;
22
-
23
- // 主函数类型(支持调用 + 属性方法)
24
- // 导入 Vue 类型(需安装 @vue/runtime-core)
25
- import type { App, ComponentInternalInstance } from 'vue';
26
-
27
- // 扩展 EtherreqStatic 类型,添加 install 方法
28
- interface EtherreqStatic extends EtherRequestMethod {
29
- get: EtherRequestMethod;
30
- post: EtherRequestMethod;
31
- put: EtherRequestMethod;
32
- delete: EtherRequestMethod;
33
- del: EtherRequestMethod;
34
- login: EtherRequestMethod;
35
- install: (app: App | any, options?: { baseURL?: string }) => void; // 兼容 Vue2/Vue3
36
- }
37
-
38
- // 声明组合式函数类型
39
- export function useEtherReq(): EtherreqStatic;
40
-
41
- // 导出对象
42
- declare const etherreq: EtherreqStatic;
43
-
44
- declare module 'etherreq' {
45
- export const etherreq: EtherreqStatic;
46
- export let baseURL: string;
47
- export function setBaseURL(url: string): void;
48
- }
49
-
50
- export { etherreq };
package/src/upload.js DELETED
@@ -1,88 +0,0 @@
1
- // src/upload.js
2
- import { etherreq } from './index.js';
3
-
4
- /**
5
- * 分片上传配置项
6
- * @typedef {Object} ChunkedUploadOptions
7
- * @property {number} chunkSize 分片大小,默认 5MB
8
- * @property {function(number): void} onProgress 进度回调
9
- * @property {boolean} resume 是否启用断点续传
10
- */
11
-
12
- /**
13
- * 大文件分片上传
14
- * @param {string} url 接口地址
15
- * @param {File|Blob} file 文件对象
16
- * @param {ChunkedUploadOptions} [options] 配置项
17
- */
18
- export async function uploadLargeFile(url, file, options = {}) {
19
- const { chunkSize = 5 * 1024 * 1024, onProgress = () => {}, resume = true } = options;
20
-
21
- const totalChunks = Math.ceil(file.size / chunkSize);
22
- const uploadedChunks = await getUploadedChunks(url, file, totalChunks, resume);
23
-
24
- let current = 0;
25
-
26
- for (let i = 0; i < totalChunks; i++) {
27
- if (uploadedChunks.includes(i)) {
28
- current++;
29
- onProgress(Math.round((current / totalChunks) * 100));
30
- continue;
31
- }
32
-
33
- const start = i * chunkSize;
34
- const end = Math.min(start + chunkSize, file.size);
35
- const chunk = file.slice(start, end);
36
-
37
- const formData = new FormData();
38
- formData.append('file', chunk);
39
- formData.append('chunkIndex', i);
40
- formData.append('totalChunks', totalChunks);
41
- formData.append('fileName', file.name);
42
-
43
- try {
44
- await etherreq.post(url, formData, {
45
- headers: {
46
- 'Content-Type': 'multipart/form-data',
47
- },
48
- });
49
-
50
- current++;
51
- onProgress(Math.round((current / totalChunks) * 100));
52
- } catch (error) {
53
- console.error(`上传分片 ${i} 失败`, error);
54
- throw error;
55
- }
56
- }
57
-
58
- // 合并请求
59
- await etherreq.post(`${url}/complete`, {
60
- fileName: file.name,
61
- totalChunks,
62
- });
63
-
64
- return {
65
- fileName: file.name,
66
- size: file.size,
67
- status: 'completed',
68
- };
69
- }
70
-
71
- /**
72
- * 获取已上传的分片索引(用于断点续传)
73
- * @param {string} uploadUrl
74
- * @param {File} file
75
- * @param {number} totalChunks
76
- * @param {boolean} enableResume
77
- * @returns {Promise<number[]>}
78
- */
79
- async function getUploadedChunks(uploadUrl, file, totalChunks, enableResume) {
80
- if (!enableResume) return [];
81
-
82
- try {
83
- const res = await etherreq.get(`${uploadUrl}?check=1&fileName=${encodeURIComponent(file.name)}&totalChunks=${totalChunks}`);
84
- return res.data.uploadedChunks || [];
85
- } catch (e) {
86
- return [];
87
- }
88
- }