Skip to content

Commit 42de1e0

Browse files
committed
feat: add abort
1 parent 9b9ba02 commit 42de1e0

File tree

5 files changed

+88
-44
lines changed

5 files changed

+88
-44
lines changed

CHANGELOG.md

+35-34
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,45 @@
11
## v1.18.0
2-
- 重构了xhr逻辑
3-
- 移除了fake模式,支持规则内配置,粒度更小了,使用`faked`字段
2+
- 重构了 xhr 逻辑
3+
- 移除了 fake 模式,支持规则内配置,粒度更小了,使用`faked`字段
44
- 添加新的模式,代理模式
5-
- 规则中新增blocked、faked字段
5+
- 规则中新增 blocked、faked 字段
66
- 新增onBlocking hook
77
- 新增支持event-source-stream,配套的字段(chunks, chunkInterval, chunkTemplate)
88
- 支持更细粒度的修改headers
9+
- 完善功能支持 abort 操作
910

1011
## v1.17.0
11-
- 支持whiteList配置
12+
- 支持 whiteList 配置
1213
- 修复了xhr fake模式下不生效的问题
1314

1415
## v1.16.1
15-
- 支持font类型资源的拦截
16+
- 支持 font 类型资源的拦截
1617

1718
## v1.16.0
18-
- 更新icon
19-
- vite更新到5.0,antd更新到5.0
19+
- 更新 icon
20+
- vite 更新到 5.0,antd 更新到5.0
2021
- 添加禁用类型,可设置禁用 xhr 或 fetch
21-
- 添加插件拦截时机,可设置start end delay trigger override
22-
- 修复fake不生效的问题
22+
- 添加插件拦截时机,可设置 start end delay trigger override
23+
- 修复 fake 不生效的问题
2324

2425
## v1.15.0
25-
- 添加run at功能
26+
- 添加 run at 功能
2627

2728
## v1.14.4
2829
- 修复页面刷新时,工作空间没有数据没有更新的问题
29-
- 更改license
30+
- 更改 license
3031

3132
## v1.14.3
32-
- 添加onRedirect、onResponseHeaders、 onRequestHeaders钩子
33-
- 支持拦截重定向css js类型的资源
33+
- 添加 onRedirect、onResponseHeaders、 onRequestHeaders 钩子
34+
- 支持拦截重定向 css js 类型的资源
3435
- 优化列表信息展示
3536

3637
## v1.14.0
37-
- 添加groupId字段,支持工作空间
38+
- 添加 groupId 字段,支持工作空间
3839

3940
## v1.13.0
40-
- 优化injected script的运行逻辑
41-
- 修改code面板的处理逻辑,增加ts提示逻辑
41+
- 优化 injected script 的运行逻辑
42+
- 修改 code 面板的处理逻辑,增加 ts 提示逻辑
4243
- 添加配置面板
4344
- 优化暗色模式
4445

@@ -49,56 +50,56 @@
4950
- 拦截开关
5051

5152
## v.1.11.0
52-
- 迁移到react18
53-
- 配置规则中添加params的判断
54-
- 添加description选项
55-
- 修复搜索bug
53+
- 迁移到 react 18
54+
- 配置规则中添加 params 的判断
55+
- 添加 description 选项
56+
- 修复搜索 bug
5657
- 添加多语言
5758

5859
## v.1.10.3
59-
- 调整type选项,缺省时自动匹配
60+
- 调整 type 选项,缺省时自动匹配
6061

6162
## v.1.10.2
62-
- 添加type型列
63+
- 添加 type 型列
6364

6465
## v.1.10.1
65-
- 添加了test, type选项
66+
- 添加了 test, type 选项
6667

6768
## v.1.10.0
68-
- 添加了fetch
69+
- 添加了 fetch
6970

7071
## v1.8.0
71-
- 添加了redirectUrl
72+
- 添加了 redirectUrl
7273

7374
## v1.7.2
7475

75-
- 替换minimatch
76+
- 替换 minimatch
7677

7778
## v1.7.1
7879

79-
- 重写fakeXhr setResponseHeaders
80-
- 添加patch类型
80+
- 重写 fakeXhr setResponseHeaders
81+
- 添加 patch 类型
8182

8283
## v1.7.0
8384

84-
- 添加faked选项,用于适应不同的使用场景
85+
- 添加 faked 选项,用于适应不同的使用场景
8586

8687
## v1.6.3
8788

88-
- 修复编辑器json校验问题
89+
- 修复编辑器 json 校验问题
8990

9091
## v1.6.2
9192

92-
- 添加local版本
93+
- 添加 local 版本
9394

9495
## v1.6.1
9596

96-
- 实现require机制,通过cdn引入minimatch
97+
- 实现 require 机制,通过 cdn 引入 minimatch
9798
- 修复筛选bug
9899

99100
## v1.6
100101

101-
- 使用glob规则匹配url,移除正则匹配
102+
- 使用 glob 规则匹配 url,移除正则匹配
102103
- 扁平数据管理,支持过滤字段
103104
- 支持修改响应头
104-
- 使用cdn,大幅度缩减安装包
105+
- 使用 cdn,大幅度缩减安装包

src/injected/proxy/fetch.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { asyncGenerator, createRunFunc, delayAsync, formatChunk, parseHeaderKey
66
import { log } from "../../tools/log";
77
import { parseUrl } from "../../tools";
88
import { Options, __global__, getPageFetch } from "./globalVar";
9+
import { createBlockException } from "../../tools/exception";
910

1011
let unproxied = true
1112

@@ -68,7 +69,7 @@ export function proxyFetch(options: Options) {
6869
url: url.origin + url.pathname,
6970
}) || matchItem.blocked
7071
if (blocked) {
71-
throw new Error('net::ERR_BLOCKED_BY_CLIENT')
72+
throw createBlockException()
7273
}
7374
}
7475

@@ -79,19 +80,32 @@ export function proxyFetch(options: Options) {
7980
: await realFetch.call(thisArg, input, init)
8081
const response = await onFetchIntercept!(matchItem)(realResponse)
8182

83+
const abortController = new AbortController()
84+
85+
init.signal?.addEventListener('abort', () => {
86+
abortController.abort()
87+
return
88+
})
89+
8290
return delayAsync(async () => {
8391
let res: Response = response || realResponse
8492

8593
if (isEventSource) {
94+
let outterController: ReadableStreamDefaultController
8695
res = new Response(new ReadableStream({
8796
async start(controller) {
97+
outterController = controller
8898
for await (const value of asyncGenerator(chunks, matchItem.chunkInterval)) {
8999
const str = formatChunk(value, matchItem.chunkTemplate)
90100
controller.enqueue(new TextEncoder().encode(str));
91101
}
92102
controller.close();
93103
},
94104
}), init)
105+
init.signal?.addEventListener('abort', (event: any) => {
106+
outterController.close()
107+
throw new Error(event.target.reason)
108+
})
95109
}
96110

97111
if (loggable) {
@@ -106,7 +120,7 @@ export function proxyFetch(options: Options) {
106120
}
107121

108122
return res
109-
}, matchItem.delay)
123+
}, matchItem.delay, abortController.signal)
110124
}
111125

112126
const response = __global__.PageFetch

src/injected/proxy/handle.ts

+18-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { log } from "../../tools/log"
99
import { parseUrl, stringifyHeaders } from "../../tools"
1010
import { HttpStatusCodes } from "./constants"
1111
import { Options, __global__, getPageXhr } from "./globalVar"
12+
import { ExtensionName } from "../../tools/constants"
13+
import { createBlockException } from "../../tools/exception"
1214

1315
export interface ProxyXMLHttpRequest extends XMLHttpRequest {
1416
_async: boolean
@@ -71,11 +73,14 @@ function dispatchCustomEvent(this: ProxyXMLHttpRequest, type: string) {
7173
export function proxyFakeXhrInstance(this: ProxyXMLHttpRequest, options: Options) {
7274
const originOpen = this.open
7375
const originSend = this.send
76+
const originAbort = this.abort
7477
const originSetRequestHeader = this.setRequestHeader
7578
const originGetResponseHeader = this.getResponseHeader
7679
const originGetAllResponseHeaders = this.getAllResponseHeaders
7780
const originOverrideMimeType = this.overrideMimeType
7881

82+
const controller = new AbortController()
83+
7984
this.open = (method: string, url: string | URL, async: boolean = true) => {
8085
this._async = async
8186
this._url = url
@@ -124,16 +129,16 @@ export function proxyFakeXhrInstance(this: ProxyXMLHttpRequest, options: Options
124129
url: this._url,
125130
}) || matchItem.blocked
126131
if (blocked) {
127-
reject(new Error('net::ERR_BLOCKED_BY_CLIENT'))
132+
reject(createBlockException())
128133
} else {
129-
delayAsync(resolve, matchItem.delay)
134+
delayAsync(() => resolve(undefined), matchItem.delay, controller.signal)
130135
}
131136
} else {
132137
const innerXhr = new PageXhr()
133138
innerXhr.open(this._method, this._url, this._async)
134-
delayAsync(() => innerXhr.send(body), matchItem.delay)
139+
delayAsync(() => innerXhr.send(body), matchItem.delay, controller.signal)
135140
innerXhr.onload = () => resolve(innerXhr)
136-
innerXhr.onerror = () => reject()
141+
innerXhr.onerror = reject
137142
}
138143
})
139144
}
@@ -250,6 +255,15 @@ export function proxyFakeXhrInstance(this: ProxyXMLHttpRequest, options: Options
250255
}
251256
this._forceMimeType = toTitleCase(mimeType)
252257
}
258+
this.abort = () => {
259+
if (! this._matchItem) {
260+
originAbort.call(this)
261+
return
262+
}
263+
if (this._async !== false) {
264+
controller.abort()
265+
}
266+
}
253267

254268
return this
255269
}

src/tools/exception.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { ExtensionName } from "./constants";
2+
3+
export function createBlockException() {
4+
return new Error('Error blocked by ' + ExtensionName)
5+
}

src/tools/index.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function formatChunk(chunk: string, tpl = 'data: $1\n\n') {
1010
return tpl.replace('$1', chunk)
1111
}
1212

13-
export async function* asyncGenerator(data: unknown[], delay = 1000) {
13+
export async function* asyncGenerator(data: unknown[], delay = 1000, signal?: AbortSignal) {
1414
const list = data.map(item => typeof item !== 'string' ? JSON.stringify(item) : item)
1515
for (const item of list) {
1616
await new Promise(resolve => setTimeout(resolve, delay))
@@ -250,10 +250,20 @@ export function trimUrlParams(url: string) {
250250
return url.replace(/\?(.*)/, '')
251251
}
252252

253-
export function delayAsync<T extends (...args: any[]) => any>(fn: T, delay: number | undefined) {
254-
return new Promise<Awaited<ReturnType<T>>>(resolve => {
253+
export function delayAsync<T extends (signal: AbortSignal) => any>(fn: T, delay: number | undefined, signal?: AbortSignal) {
254+
const controller = new AbortController()
255+
const mergedSignal = signal || controller.signal
256+
return new Promise<Awaited<ReturnType<T>>>((resolve, reject) => {
257+
mergedSignal.addEventListener('abort', (event: any) => {
258+
reject(event.target.reason)
259+
return
260+
})
261+
255262
setTimeout(() => {
256-
resolve(fn())
263+
if (mergedSignal.aborted) {
264+
return
265+
}
266+
resolve(fn(mergedSignal))
257267
}, delay)
258268
})
259269
}

0 commit comments

Comments
 (0)