URL工具类

/**
 * @author: 苗士军
 * @description URL工具类
 */
UrlUtils = {
    /**
     * @description 判断url是否存在(存在跨域问题)
     * @param _url
     * @return {boolean}
     */
    isTrueUrl: function (_url) {
        result = false;
        if (_url == undefined || _url == '') {
            return result;
        }
        $.ajax({
            url: _url,
            type: "get",
            async: false,
            success: function () {
                result = true;
            },
            statusCode: {
                404: function () {
                }
            }
        });
        return result;
    },
    /**
     * @description 解析url
     * @param url
     * @return {{source: *, protocol, host: string, port: (*|Function|string), query: (*|string), params, file: *, hash, path: string, relative: *, segments: Array}}
     */
    parseURL: function (url) {
        var a = document.createElement('a');
        a.href = url;
        return {
            source: url,
            protocol: a.protocol.replace(':', ''),
            host: a.hostname,
            port: a.port,
            query: a.search,
            params: (function () {
                var ret = {},
                    seg = a.search.replace(/^\?/, '').split('&'),
                    len = seg.length, i = 0, s;
                for (; i < len; i++) {
                    if (!seg[i]) {
                        continue;
                    }
                    s = seg[i].split('=');
                    ret[s[0]] = s[1];
                }
                return ret;
            })(),
            file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
            hash: a.hash.replace('#', ''),
            path: a.pathname.replace(/^([^\/])/, '/$1'),
            relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],
            segments: a.pathname.replace(/^\//, '').split('/')
        };
    },
    /**
     * @description 解析url获取参数
     * @param path
     * @return {{}}
     */
    getParam: function (path) {
        var result = {}, param = /([^?=&]+)=([^&]+)/ig, match;
        while ((match = param.exec(path)) != null) {
            result[match[1]] = match[2];
        }
        return result;
    }
}
/**
 * URL 工具类
 */
class UrlUtils {
    /**
     * 检查 URL 是否可访问
     * @param {string} url URL 地址
     * @param {Object} options 配置选项
     * @param {string} options.method 请求方法
     * @param {number} options.timeout 超时时间(毫秒)
     * @return {Promise<boolean>} 是否可访问
     */
    static async isUrlAccessible(url, options = {}) {
        if (!url) {
            return false;
        }

        const { method = 'HEAD', timeout = 3000 } = options;

        try {
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), timeout);

            const response = await fetch(url, {
                method,
                mode: 'cors',
                cache: 'no-cache',
                signal: controller.signal
            });

            clearTimeout(timeoutId);
            return response.ok;
        } catch (error) {
            return false;
        }
    }

    /**
     * 解析 URL
     * @param {string} url URL 地址
     * @return {Object} 解析结果
     */
    static parseUrl(url) {
        if (!url) {
            throw new Error('URL 不能为空');
        }

        const a = document.createElement('a');
        a.href = url;

        return {
            source: url,
            protocol: a.protocol.replace(':', ''),
            host: a.hostname,
            port: a.port || (a.protocol === 'https:' ? '443' : '80'),
            query: a.search,
            params: this.getParams(url),
            file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
            hash: a.hash.replace('#', ''),
            path: a.pathname.replace(/^([^\/])/, '/$1'),
            relative: (a.href.match(/https?:\/\/[^\/]+(.+)/) || [, ''])[1],
            segments: a.pathname.replace(/^\//, '').split('/')
        };
    }

    /**
     * 获取 URL 参数
     * @param {string} url URL 地址
     * @return {Object} 参数对象
     */
    static getParams(url) {
        if (!url) {
            return {};
        }

        const result = {};
        const paramRegex = /([^?=&]+)=([^&]+)/ig;
        let match;

        while ((match = paramRegex.exec(url)) !== null) {
            try {
                result[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
            } catch (error) {
                result[match[1]] = match[2];
            }
        }

        return result;
    }

    /**
     * 构建 URL
     * @param {string} baseUrl 基础 URL
     * @param {Object} params 参数对象
     * @return {string} 构建后的 URL
     */
    static buildUrl(baseUrl, params = {}) {
        if (!baseUrl) {
            throw new Error('基础 URL 不能为空');
        }

        const url = new URL(baseUrl);
        Object.entries(params).forEach(([key, value]) => {
            if (value !== undefined && value !== null) {
                url.searchParams.append(key, value);
            }
        });

        return url.toString();
    }

    /**
     * 向 URL 添加参数
     * @param {string} url URL 地址
     * @param {Object} params 要添加的参数
     * @return {string} 新的 URL
     */
    static addParams(url, params = {}) {
        if (!url) {
            throw new Error('URL 不能为空');
        }

        const urlObj = new URL(url);
        Object.entries(params).forEach(([key, value]) => {
            if (value !== undefined && value !== null) {
                urlObj.searchParams.set(key, value);
            }
        });

        return urlObj.toString();
    }

    /**
     * 从 URL 中移除参数
     * @param {string} url URL 地址
     * @param {Array<string>} paramNames 要移除的参数名
     * @return {string} 新的 URL
     */
    static removeParams(url, paramNames = []) {
        if (!url) {
            throw new Error('URL 不能为空');
        }

        const urlObj = new URL(url);
        paramNames.forEach(name => {
            urlObj.searchParams.delete(name);
        });

        return urlObj.toString();
    }

    /**
     * 验证 URL 格式
     * @param {string} url URL 地址
     * @return {boolean} 是否为有效 URL
     */
    static isValidUrl(url) {
        try {
            new URL(url);
            return true;
        } catch (error) {
            return false;
        }
    }

    /**
     * 计算相对路径
     * @param {string} from 起始 URL
     * @param {string} to 目标 URL
     * @return {string} 相对路径
     */
    static getRelativePath(from, to) {
        if (!from || !to) {
            throw new Error('起始和目标 URL 不能为空');
        }

        const fromUrl = new URL(from);
        const toUrl = new URL(to);

        if (fromUrl.origin !== toUrl.origin) {
            return to;
        }

        const fromPath = fromUrl.pathname.split('/').filter(Boolean);
        const toPath = toUrl.pathname.split('/').filter(Boolean);

        let commonLength = 0;
        while (commonLength < fromPath.length && commonLength < toPath.length && 
               fromPath[commonLength] === toPath[commonLength]) {
            commonLength++;
        }

        const relativeParts = Array(fromPath.length - commonLength).fill('..');
        relativeParts.push(...toPath.slice(commonLength));

        let relativePath = relativeParts.join('/');
        if (toUrl.search) {
            relativePath += toUrl.search;
        }
        if (toUrl.hash) {
            relativePath += toUrl.hash;
        }

        return relativePath || '.';
    }
}
// 检查 URL 是否可访问
UrlUtils.isUrlAccessible('https://www.example.com')
    .then(accessible => console.log('URL 可访问:', accessible));

// 解析 URL
const parsed = UrlUtils.parseUrl('https://www.example.com/path?a=1&b=2#hash');
console.log('解析结果:', parsed);

// 构建 URL
const url = UrlUtils.buildUrl('https://www.example.com', { a: 1, b: 2 });
console.log('构建的 URL:', url);

// 验证 URL
console.log('URL 有效:', UrlUtils.isValidUrl('https://www.example.com'));
posted @ 2019-04-09 15:59  苗士军  阅读(520)  评论(0)    收藏  举报