Skip to content
Closed

xhr #861

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/app/service/offscreen/gm_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ export default class GMApi {
statusText: xhr.statusText,
// header由service_worker处理,但是存在特殊域名(例如:edge.microsoft.com)无法获取的情况,在这里增加一个默认值
responseHeaders: xhr.getAllResponseHeaders(),
responseType: details.responseType,
responseType: details.responseType, // **** 概念错误. Xhr的responseType是用来在最终内容判断时做相应的处理,不是拿来直接当 xhr的responseType. 假如 response status 不是 2xx, response type 不是 basic, responseType 就不会是 Xhr 的要求 responseType ****
};
if (xhr.readyState === 4) {
const responseType = details.responseType?.toLowerCase();
const responseType = details.responseType?.toLowerCase(); // **** 概念错误 ****
if (responseType === "arraybuffer" || responseType === "blob") {
// **** 概念错误. Blob型 (包括stream) 的response都应该用progressive body getReader 不断 read. 而不用考虑是progressive与否 ****
const xhrResponse = xhr.response;
if (xhrResponse === null) {
response.response = null;
Expand Down
44 changes: 42 additions & 2 deletions src/app/service/service_worker/gm_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ export default class GMApi {
status: response.status,
statusText: response.statusText,
responseHeaders: respHeader,
responseType: config.responseType,
responseType: config.responseType, // **** 概念错误. Xhr的responseType是用来在最终内容判断时做相应的处理,不是拿来直接当 xhr的responseType. 假如 response status 不是 2xx, response type 不是 basic, responseType 就不会是 Xhr 的要求 responseType ****
};
if (resultParam) {
respond.status = respond.status || resultParam.statusCode;
Expand Down Expand Up @@ -683,10 +683,50 @@ export default class GMApi {
if (!reader) {
throw new Error("read is not found");
}
const readData = ({ done, value }: { done: boolean; value?: Uint8Array }) => {
const chunks = [] as Uint8Array<ArrayBufferLike>[];
let receivedLength = 0;
const readData = async ({ done, value }: { done: boolean; value?: Uint8Array }) => {
if (value?.length) {
chunks.push(value);
receivedLength += value.length;
}
if (done) {
const data = this.dealFetch(config, resp, 4, resultParam);
data.responseHeaders = resultParam.responseHeader || data.responseHeaders;

// 真正的 responseType 在这里处理!

if (resp.type === "basic" && resp.ok) {
if (!data.responseType || data.responseText === "text") {
// 因为现在用了 body.getReader().read(), 所以 response body 被 consume了,不能用 await response.text()

// 检查 Content-Type 中的 charset
const contentType = resp.headers.get("content-type") || "";
const charsetMatch = contentType.match(/charset=([^;]+)/i);
const charset = charsetMatch ? charsetMatch[1].toLowerCase() : "utf-8";

// 合并分片(chunks)
const chunksAll = new Uint8Array(receivedLength);
let position = 0;
for (const chunk of chunks) {
chunksAll.set(chunk, position);
position += chunk.length;
}

// 使用检测到的 charset 解码
let textDecoded;
try {
textDecoded = new TextDecoder(charset).decode(chunksAll);
} catch (e: any) {
throw new Error(`Failed to decode response with charset ${charset}: ${e.message}`);
}
if (typeof textDecoded === "string" && textDecoded.length > 0) {
data.response = textDecoded;
data.responseType = "text";
}
}
// 还要处理其他类型
}
msgConn.sendMessage({
action: "onreadystatechange",
data: data,
Expand Down
Loading