Skip to content

Http请求 ​

URL解析 ​

常用取值方式 ​

ts
// 完整 URL
window.location.href      // "https://www.example.com/path/page?id=123&name=test#section"

// 拆分各部分
window.location.protocol  // "https:"
window.location.host      // "www.example.com"        (域名+端口)
window.location.hostname  // "www.example.com"        (仅域名)
window.location.port      // "8080"                   (端口号,默认端口返回空字符串)
window.location.pathname  // "/path/page"             (路径)
window.location.search    // "?id=123&name=test"      (查询参数,含 ?)
window.location.hash      // "#section"               (锚点,含 #)

解析查询参数 ​

不要手动 split search,直接用原生 API

方法作用返回值
get(name)获取第一个值string | null
getAll(name)获取所有同名值string[]
has(name)判断参数是否存在boolean
set(name, value)设置/覆盖(去重)void
append(name, value)追加(保留多个同名)void
delete(name)删除参数void
toString()序列化为查询字符串(不含?)string

示例

new URLSearchParams()

ts
const params = new URLSearchParams(window.location.search);
params.get('id')       // "123"
params.get('name')     // "test"
params.has('token')    // true / false
params.getAll('tag')   // ["a", "b"]  (同名参数多个值)

new URL()

ts
const url = new URL('https://example.com/list?page=2&sort=name&tag=js&tag=ts');

url.searchParams.get('page');   // "2"
url.searchParams.get('sort');   // "name"
ts
const CookieUtil = {
    /**
     * 增加/修改cookie
     * @param {string} name 属性名
     * @param {string} value 属性值
     * @param {object} options 可选参数,包含过期时间、路径、是否安全、是否HttpOnly、SameSite策略
     * @param {number} options.days 过期时间,单位为天,默认为1天
     * @param {string} options.Path cookie的路径,默认为'/'
     * @param {boolean} options.Secure 是否为安全cookie,默认为false
     * @param {boolean} options.HttpOnly 是否为HttpOnly cookie,默认为false
     * @param {string} options.SameSite SameSite策略,可选值为'Lax'、'Strict'、'None',默认为'Lax'
     */
    set(name: string, value: string, { days = 1, Path = '/', Secure = false, HttpOnly = false, SameSite = 'Lax'} = {}): void {
        // 计算过期时间,单位为秒
        const maxAge = days * 24 * 60 * 60;
        // 设置cookie,使用 encodeURIComponent 对属性值进行编码,防止特殊字符导致的错误,path=/表示在整个域名下都可访问
        document.cookie = `${name}=${encodeURIComponent(value)}; Max-Age=${maxAge}; Path=${Path}; ${Secure ? 'Secure; ' : ''}${HttpOnly ? 'HttpOnly; ' : ''}SameSite=${SameSite};`;
    },

    /**
     * 获取cookie
     * @param {string} name 属性名
     * @returns {string|null} 属性值,不存在时返回 null
     */
    get(name: string): string | null {
        // 使用正则表达式匹配 cookie 中的指定属性名,并获取其对应的属性值
        const match = document.cookie.match(new RegExp('(?:^|;\\s*)' + name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '=([^;]*)'));
        // 如果匹配成功,返回解码后的属性值,否则返回 null
        return match ? decodeURIComponent(match[1]) : null;
    },

    /**
     * 删除cookie
     * @param {string} name 属性名
     * @param {object} options 可选参数,包含cookie的路径
     * @param {string} options.Path cookie的路径,默认为'/'
     */
    remove(name: string, { Path = '/' } = {}): void {
        // 设为-1天,立即过期
        document.cookie = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${Path}`;
    },

    /**
     * 一键删除指定路径下的所有cookie,无法删除 HttpOnly 和子域 cookie
     * @param {string} Path cookie的路径,默认为'/'
     */
    clearAll(Path = '/'): void {
        // 无cookie时直接跳过
        if (!document.cookie) return;
        // 使用 forEach 遍历 document.cookie.split(';'),对每个 cookie 字符串进行处理
        document.cookie.split(';').forEach(cookie => {
            // 分割出key
            const name = cookie.split('=')[0].trim();
            // key存在直接删除
            name && this.remove(name, { Path });
        });
    }
};

fetch请求【可取消上一个请求】 ​

ts
// 用于记录上一个http请求【当有新请求时,可用于取消上一个http请求】
let currentController: AbortController | undefined;

const http = async () => {
    // 每次回调时重新创建控制器,确保 signal 是全新的
    const controller = new AbortController();
    // 信号
    const signal = controller.signal;

    // 如果上一个请求未完成,则直接取消
    currentController && currentController.abort();
    // 把最新的请求存储到外部,方便清理
    currentController = controller;

    try {
        // 发送请求
        const sendHttp = await fetch(`https://api.xxx-xxx-xxx.com/API`, {
            method: 'POST',
            signal: signal, // 绑定取消信号
            headers: {
                'Content-Type': 'application/json' // 告诉服务器发送的是 JSON 数据
            },
            body: JSON.stringify({
                // Parse: ''
            }) // 【关键】将数据转换为 JSON 字符串放入请求体
        });
        // 转换json数据
        const httpResult = await sendHttp.json();

        // 后续业务逻辑
    } catch (error: any) {
        // error.name='AbortError' 表示主动取消,不需要提醒
        if(error.name === 'AbortError') return;

        // 后续错误处理
    }
};

fetch上传文件、图片【多个】 ​

ts
// 用于记录上一个http请求【当有新请求时,可用于取消上一个http请求】
let currentController: AbortController | undefined;

const uploadImageorFile = async (files: Array<File>) => {
    // 每次回调时重新创建控制器,确保 signal 是全新的
    const controller = new AbortController();
    // 信号
    const signal = controller.signal;

    // 如果上一个请求未完成,则直接取消
    currentController && currentController.abort();
    // 把最新的请求存储到外部,方便清理
    currentController = controller;

    // 构建 FormData
    const formData = new FormData();
    // 遍历所有选中的文件
    for (let i = 0; i < files.length; i++) {
        // 【files】为后端接收的字段名称
        formData.append('files', files[i]!);
        
        /** 参数1 (参数名/字段名) ;参数2:value (值/内容);参数3:filename (文件名) —— 可选 **/
        // formData.append(name, blob, 'filename.txt'); 【也可以传blob】
    }

    try {
        // 发送请求
        const sendHttp = await fetch('https://api.xxx.com/upload', {
            // 请求模式
            method: 'POST',
            // 绑定取消信号
            signal: signal,
            // 请求体
            body: formData,
            // 请求头配置
            headers: {
                //  不要手动设置 Content-Type!【FormData 作为 body 时,浏览器会自动设置:】
            }
        });

        // 当 HTTP 状态码在 200~299 之间时,ok 为 true
        // 其他情况(如 404、500)都是 false
        // 作用:抛出一个错误,让代码跳到 catch 里
        if (!sendHttp.ok) throw new Error(`HTTP error! status: ${sendHttp.status}`);

        // 转换json数据
        const httpResult = await sendHttp.json();
        
        // 后续业务逻辑
    } catch (error: any) {
        // error.name='AbortError' 表示主动取消,不需要提醒
        if(error.name === 'AbortError') return;

        // 后续错误处理
    }
};

Copyright © 2026 Luke