etherreq 1.2.1 → 1.2.2

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/dist/cache.js CHANGED
@@ -7,8 +7,8 @@ function hashString(str) {
7
7
  let hash = 0;
8
8
  for (let i = 0; i < str.length; i++) {
9
9
  const char = str.charCodeAt(i);
10
- hash = ((hash << 5) - hash) + char;
11
- hash = hash & hash; // 转换为32位整数
10
+ hash = (hash << 5) - hash + char;
11
+ hash |= 0; // 转换为32位整数
12
12
  }
13
13
  return Math.abs(hash).toString(36);
14
14
  }
@@ -18,9 +18,9 @@ function hashString(str) {
18
18
  */
19
19
  function isLocalStorageAvailable() {
20
20
  try {
21
- const testKey = '__storage_test__';
22
- localStorage.setItem(testKey, 'test');
23
- localStorage.removeItem(testKey);
21
+ const test = '__storage_test__';
22
+ localStorage.setItem(test, test);
23
+ localStorage.removeItem(test);
24
24
  return true;
25
25
  }
26
26
  catch (e) {
@@ -34,15 +34,19 @@ function isLocalStorageAvailable() {
34
34
  * @returns 缓存键字符串
35
35
  */
36
36
  export function getCacheKey(url, options) {
37
- const rawParams = options.params || {};
38
- // 将所有值转换为 string
39
- const stringifiedParams = {};
40
- for (const [key, value] of Object.entries(rawParams)) {
41
- stringifiedParams[key] = String(value);
37
+ // 仅对GET请求添加参数到缓存键中
38
+ if (options.method.toUpperCase() !== 'GET') {
39
+ return hashString(url);
42
40
  }
43
- const params = new URLSearchParams(stringifiedParams);
44
- const keyString = `${options.method}:${url}?${params.toString()}`;
45
- return `etherreq_cache_${hashString(keyString)}`;
41
+ // 将参数按字母顺序排序以确保一致的缓存键
42
+ if (options.params) {
43
+ const sortedParams = Object.keys(options.params)
44
+ .sort()
45
+ .map(key => `${key}=${options.params[key]}`)
46
+ .join('&');
47
+ return hashString(`${url}?${sortedParams}`);
48
+ }
49
+ return hashString(url);
46
50
  }
47
51
  /**
48
52
  * 内存缓存存储类
@@ -69,7 +73,7 @@ class MemoryCache {
69
73
  cleanupExpired() {
70
74
  const now = Date.now();
71
75
  for (const [key, entry] of this.store.entries()) {
72
- if (entry.expireAt <= now) {
76
+ if (entry.expireAt < now) {
73
77
  this.store.delete(key);
74
78
  }
75
79
  }
@@ -86,14 +90,14 @@ class MemoryCache {
86
90
  */
87
91
  get(key) {
88
92
  const entry = this.store.get(key);
89
- if (entry && entry.expireAt > Date.now()) {
90
- return entry.value;
93
+ if (!entry) {
94
+ return null;
91
95
  }
92
- // 过期则删除
93
- if (entry) {
96
+ if (entry.expireAt < Date.now()) {
94
97
  this.store.delete(key);
98
+ return null;
95
99
  }
96
- return null;
100
+ return entry.value;
97
101
  }
98
102
  /**
99
103
  * 删除指定缓存
@@ -127,7 +131,7 @@ class MemoryCache {
127
131
  * 本地存储缓存类
128
132
  */
129
133
  class LocalStorageCache {
130
- constructor(prefix = 'etherreq_') {
134
+ constructor(prefix = 'etherreq_cache_') {
131
135
  this.prefix = prefix;
132
136
  this.available = isLocalStorageAvailable();
133
137
  }
@@ -138,12 +142,14 @@ class LocalStorageCache {
138
142
  if (!this.available)
139
143
  return;
140
144
  try {
141
- const expireAt = Date.now() + ttl;
142
- const entry = { value, expireAt };
143
- localStorage.setItem(`${this.prefix}${key}`, JSON.stringify(entry));
145
+ const item = {
146
+ value,
147
+ expireAt: Date.now() + ttl,
148
+ };
149
+ localStorage.setItem(this.prefix + key, JSON.stringify(item));
144
150
  }
145
- catch (error) {
146
- console.warn('LocalStorage缓存设置失败:', error);
151
+ catch (e) {
152
+ console.warn('Cache set failed:', e);
147
153
  }
148
154
  }
149
155
  /**
@@ -153,21 +159,19 @@ class LocalStorageCache {
153
159
  if (!this.available)
154
160
  return null;
155
161
  try {
156
- const item = localStorage.getItem(`${this.prefix}${key}`);
157
- if (!item)
162
+ const itemStr = localStorage.getItem(this.prefix + key);
163
+ if (!itemStr) {
158
164
  return null;
159
- const entry = JSON.parse(item);
160
- if (entry.expireAt > Date.now()) {
161
- return entry.value;
162
165
  }
163
- else {
164
- // 过期则删除
165
- localStorage.removeItem(`${this.prefix}${key}`);
166
+ const item = JSON.parse(itemStr);
167
+ if (item.expireAt < Date.now()) {
168
+ localStorage.removeItem(this.prefix + key);
166
169
  return null;
167
170
  }
171
+ return item.value;
168
172
  }
169
- catch (error) {
170
- console.warn('LocalStorage缓存获取失败:', error);
173
+ catch (e) {
174
+ console.error('Cache get failed:', e);
171
175
  return null;
172
176
  }
173
177
  }
@@ -191,17 +195,16 @@ class LocalStorageCache {
191
195
  if (!this.available)
192
196
  return;
193
197
  try {
194
- const keysToRemove = [];
195
198
  for (let i = 0; i < localStorage.length; i++) {
196
199
  const key = localStorage.key(i);
197
200
  if (key && key.startsWith(this.prefix)) {
198
- keysToRemove.push(key);
201
+ localStorage.removeItem(key);
202
+ i--; // 修正索引
199
203
  }
200
204
  }
201
- keysToRemove.forEach(key => localStorage.removeItem(key));
202
205
  }
203
- catch (error) {
204
- console.warn('LocalStorage缓存清空失败:', error);
206
+ catch (e) {
207
+ console.error('Cache clear failed:', e);
205
208
  }
206
209
  }
207
210
  }
@@ -276,6 +279,6 @@ class CacheFactory {
276
279
  }
277
280
  }
278
281
  // 默认导出混合缓存实例
279
- export const requestCache = CacheFactory.create('memory+local');
282
+ export const requestCache = CacheFactory.create();
280
283
  // 导出缓存工厂和工具函数
281
284
  export { CacheFactory, MemoryCache, LocalStorageCache, HybridCache, hashString, isLocalStorageAvailable };
package/dist/etherreq.js CHANGED
@@ -1,84 +1,61 @@
1
- // src/etherreq.ts
2
1
  export const create = (defaultConfig = {}) => {
3
- const interceptors = {
4
- request: [],
5
- response: [],
6
- };
7
- const use = (fulfilled, rejected, type = 'request') => {
8
- interceptors[type].push({ fulfilled, rejected });
9
- };
10
- const dispatchRequest = async (config) => {
11
- // 请求拦截器执行
12
- for (const interceptor of interceptors.request) {
13
- const nextConfig = await interceptor.fulfilled(config);
14
- // ✅ 拦截器可以返回一个 response 对象,表示中断请求
15
- if (nextConfig && nextConfig.isFromCache) {
16
- return nextConfig.data; // ✅ 直接返回缓存结果,不再往下执行
17
- }
18
- config = nextConfig;
2
+ // 拦截器存储
3
+ const requestInterceptors = [];
4
+ const responseInterceptors = [];
5
+ const client = async (config) => {
6
+ // 合并默认配置
7
+ const mergedConfig = { ...defaultConfig, ...config };
8
+ // 应用请求拦截器
9
+ let processedConfig = { ...mergedConfig };
10
+ for (const interceptor of requestInterceptors) {
11
+ processedConfig = await interceptor(processedConfig);
19
12
  }
20
- // 检查 url 是否存在
21
- if (!config.url) {
22
- throw new Error('请求配置中缺少 url 属性');
23
- }
24
- let response;
25
- const { url, method = 'GET', headers = {}, body } = config;
26
- let text = '';
27
13
  try {
28
- const options = {
29
- method,
30
- headers,
31
- body: method !== 'GET' ? JSON.stringify(body) : undefined,
32
- };
33
- const res = await fetch(url, options);
34
- text = await res.text();
35
- if (!res.ok) {
36
- throw new Error(`HTTP 错误: ${res.status} - ${res.statusText}`);
37
- }
38
- if (text.trim().startsWith('<')) {
39
- throw new Error('服务器返回了 HTML 页面,预期为 JSON 格式');
14
+ // 发送请求
15
+ const response = await fetch(processedConfig.url, {
16
+ method: processedConfig.method || 'GET',
17
+ headers: {
18
+ ...(processedConfig.headers || {}),
19
+ },
20
+ body: processedConfig.body ? JSON.stringify(processedConfig.body) : undefined,
21
+ });
22
+ // 检查响应状态
23
+ if (!response.ok) {
24
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
40
25
  }
41
- const data = JSON.parse(text);
42
- response = {
26
+ // 解析响应数据
27
+ const data = await response.json();
28
+ let responseObject = {
43
29
  data,
44
- status: res.status,
45
- statusText: res.statusText,
46
- headers: Object.fromEntries(res.headers.entries()),
47
- config,
30
+ status: response.status,
31
+ statusText: response.statusText,
32
+ headers: response.headers,
33
+ config: processedConfig,
48
34
  };
49
- }
50
- catch (error) {
51
- error.message += `\n请求地址: ${url}`;
52
- if (text) {
53
- error.message += `\n响应内容: ${text.substring(0, 200)}...`;
54
- }
55
- for (const interceptor of interceptors.response) {
56
- if (interceptor.rejected) {
57
- return interceptor.rejected(error);
58
- }
35
+ // 应用响应拦截器
36
+ for (const interceptor of responseInterceptors) {
37
+ responseObject = await interceptor(responseObject);
59
38
  }
60
- throw error;
39
+ return responseObject;
61
40
  }
62
- // 响应拦截器执行
63
- for (const interceptor of interceptors.response) {
64
- response = await interceptor.fulfilled(response);
41
+ catch (error) {
42
+ // 如果是网络错误或其他类型的错误
43
+ throw new Error(`Request failed: ${error.message}`);
65
44
  }
66
- return response;
67
- };
68
- const instance = (config) => {
69
- return dispatchRequest({
70
- ...defaultConfig,
71
- ...config,
72
- });
73
45
  };
74
- instance.use = (fulfilled, rejected) => use(fulfilled, rejected, 'request');
75
- instance.interceptors = {
46
+ // 拦截器接口
47
+ client.interceptors = {
76
48
  request: {
77
- use: (fulfilled, rejected) => use(fulfilled, rejected, 'request'),
49
+ use: (fulfilled, rejected) => {
50
+ requestInterceptors.push(fulfilled);
51
+ },
78
52
  },
79
53
  response: {
80
- use: (fulfilled, rejected) => use(fulfilled, rejected, 'response'),
54
+ use: (fulfilled, rejected) => {
55
+ responseInterceptors.push(fulfilled);
56
+ },
81
57
  },
82
58
  };
83
- return instance;
59
+ return client;
84
60
  };
61
+ export {};
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { request, baseURL as _baseURL, setBaseURL } from './request';
2
+ import { request, baseURL as _baseURL, setBaseURL } from './request.js';
3
3
  // 示例封装方法
4
4
  const createMethod = (method) => (url, data, callback) => {
5
5
  let options;
package/dist/request.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/request.ts
2
- import { create } from './etherreq';
3
- import { requestCache, getCacheKey } from './cache';
2
+ import { create } from './etherreq.js';
3
+ import { requestCache, getCacheKey } from './cache.js';
4
4
  // 创建一个带有默认配置的请求实例
5
5
  const instance = create({
6
6
  baseURL: 'https://api.example.com', // 默认基础 URL
@@ -1,4 +1,4 @@
1
- import { CacheStorage } from './types/cache';
1
+ import type { CacheStorage } from './types/cache.js';
2
2
  /**
3
3
  * 生成缓存键的哈希值,避免特殊字符和长度问题
4
4
  * @param str 输入字符串
@@ -1,13 +1,11 @@
1
- interface RequestConfig {
2
- url?: string;
3
- method?: string;
4
- headers?: Record<string, string>;
5
- body?: any;
6
- [key: string]: any;
7
- }
8
- export declare const create: (defaultConfig?: RequestConfig) => {
9
- (config: RequestConfig): Promise<any>;
10
- use(fulfilled: any, rejected: any): void;
1
+ export declare const create: (defaultConfig?: any) => {
2
+ (config: any): Promise<{
3
+ data: any;
4
+ status: number;
5
+ statusText: string;
6
+ headers: Headers;
7
+ config: any;
8
+ }>;
11
9
  interceptors: {
12
10
  request: {
13
11
  use: (fulfilled: any, rejected: any) => void;
@@ -1,5 +1,5 @@
1
- import { baseURL as _baseURL, setBaseURL } from './request';
2
- import { EtherRequestOptions } from './types/cache';
1
+ import { baseURL as _baseURL, setBaseURL } from './request.js';
2
+ import type { EtherRequestOptions } from './types/cache.js';
3
3
  export declare const etherreq: ((url: string, options?: EtherRequestOptions, callback?: (error: Error | null, data: any) => void) => Promise<any> | undefined) & {
4
4
  get: (url: string, data?: any, callback?: (error: Error | null, data: any) => void) => Promise<any> | undefined;
5
5
  post: (url: string, data?: any, callback?: (error: Error | null, data: any) => void) => Promise<any> | undefined;
@@ -1,4 +1,4 @@
1
- import { EtherRequestOptions } from './types/cache';
1
+ import type { EtherRequestOptions } from './types/cache.js';
2
2
  declare let _baseURL: string;
3
3
  /**
4
4
  * 封装 request 函数,支持 baseURL 拼接等逻辑
@@ -1,4 +1,13 @@
1
- import { CacheOptions } from './cache';
1
+ import type { CacheOptions } from './cache';
2
+ export interface RequestConfig {
3
+ url?: string;
4
+ method?: string;
5
+ headers?: Record<string, string>;
6
+ body?: any;
7
+ params?: Record<string, string | number | boolean>;
8
+ baseURL?: string;
9
+ cache?: CacheOptions | false;
10
+ }
2
11
  /**
3
12
  * 全局配置接口
4
13
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "etherreq",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "A lightweight custom HTTP request library with TypeScript support.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/types/index.d.ts",