• 自制一个可编辑QueryString的类URLModifier


    有些情况下,需要 新增/删除/替换 url中的部分Querystring中的参数,而.net自带的Uri类只能解析,不能编辑,,并且如果是Relative类型的链接,转成Uri类型之后,很多参数又不能很好的读取,因此,,,自己动手,丰衣足食,,大家不用复制文内的代码,,,文章最后,给出完整的类的代码链接,,有需要的,直接复制就行了

    使用的场景如:

    当前request的url=  https://www.xxx.com/doc/base/infrastructure.html?categoryid=5&order=2&state=2u#topoop

    在前端razor输出的时候,需要保留order和state的情况下.修改categoryid值:

        @{
            var requestUrlModifier = ViewContext.HttpContext.Request.GetDisplayUrl().ToUrlModifier();
        }
        @foreach (var category in Model.Categories)
        {
            <a href="@requestUrlModifier.Clone().ReplaceQuery("categoryID", category.CategoryID.ToStringEx()).ToString()"></a>
        }

    首先明确这个工具类的几个作用

    1,可 新增/删除/替换 链接中的QueryString 中的各个keyvalue

    2.可 替换/设置/保留 锚点anchor

    3.对原有的Host/端口/协议/路径 保留原有值

    4.最后可输出编辑后的结果

    5.对不太标准的Url或部分有问题的QueryString支持

    测试主要以下两种Url:

    1.https://www.layui.com/doc/base/infrastructure.html?=&o==ppp&&pppp=iii&o1=ooo&test2=&u#topoop

      这个链接QueryString中,除了正常的KeyValue对之外,,还有出现:

      1) =& 开头的无效字符

      2) o==ppp 中间包含两个==号的错误连续

      3) &&pppp=iii 出现 && 两个连续字符

      4) test2=& 这样的只有key,没有value

      5) &u 这样的只有key,连等号都没有的

      6) #topoop 链接后的锚点

    2.https://www.layui.com/doc/base/infrastructure.html?=&o==ppp&&pppp=iii&o1=ooo&test2=&

      1) 链接最后以 & 结尾

    3. /doc/base/infrastructure.html?=&o==ppp&&pppp=iii&o1=ooo&test2=&u#topoop

      1) 链接以 / 开头的相对链接,不包含域名信息和端口等信息

    如果还有其他情况,可以留言,增加测试用例

    由于该类在实际使用过程中,可能会频繁被调用,因此,需要尽量少的消耗资源,尽量少的变量定义

    处理的流程主要分以下几个步骤:

    1.从后往前,计算出是否包含锚点,并计算锚点所在的index1

    2.从前往后,计算出?号所在index2

    3.截取出从0到index2的所有字符

    4.从index2到锚点index1之间的字符串就是QueryString了

    5.循环判断QueryString的起始和结束index,为了去掉前后的无效字符

    6.循环获取=和&号的位置,切分字符串

    到此,完成对Url字符串的解析,,这里为什么不用正则表达式呢,,,因为第一慢,第二闲,,没事自己写,省事省空间

    接下来就上代码了,,每个处理步骤,请看代码的注释文字

    1.在构造函数中,对传入的Url进行解析操作

      private string _anchor = string.Empty;
        private string _hostAndPath =string.Empty;
        private List<(string key, string value)> _queryKeys = new List<(string key, string value)>(5);
    
    
        public UrlModifier(string url) //直接传入string,不用uri,省的相对路径下,Uri类在读取Query属性的之后报错
        {
            if (string.IsNullOrWhiteSpace(url))
            {
                return;
            }
    
            var endIndex = url.Length - 1;
    
            //从后往前扫描锚点#
            for (int i = url.Length-1; i >= 0; i--)
            {
                if (url[i]=='#')
                {
                    _anchor = url.Substring(i+1);
                    endIndex = i - 1;
                    break;
                }
    
                //防止出现无#字符的情况
                if (url[i] == '=' || url[i] == '&' || url[i] == ' ' || url[i] == '?' || url[i]=='/')
                {
                    endIndex = url.Length-1;
                    break;
                }
            }
    
            //截取域名段,包含协议,端口号等
            var hostEndIndex = endIndex;
            for (int i = 0; i < endIndex; i++)
            {
                if (url[i]=='?')  //查找?号所在index
                {
                    hostEndIndex = i - 1;
                }
            }
    
            if (hostEndIndex>0)  //如果是绝对路径的,获取Host和Path的字符串
            {
           if(url[hostEndIndex]=='?')
           {
             _hostAndPath=url.Substring(0,hostEndIndex); 
           }
           else
           {
             _hostAndPath=url.Substring(0,hostEndIndex+1);
           }
    hostEndIndex++; } if (hostEndIndex >0 && hostEndIndex < endIndex) { //排除掉使用=号或者&或者空格结尾的字符,减少后续判断的麻烦,计算出实际的结束index for (int i = endIndex; i >= hostEndIndex; i--) { var c = url[i]; if (c != '=' && c != '&' && c != ' ') { endIndex = i; break; } } var keyword = ""; var value = ""; var startIndex = 1; char lastKeyword ='' ; for (int i = hostEndIndex; i < endIndex; i++) { var c = url[i]; //排除掉使用 = 号或者 & 或者 ? 或者空格开头的字符,减少后续判断的麻烦,计算出实际起始index if (c != '=' && c != '&' && c != ' ' && c!='?') { startIndex = i; break; } } if (startIndex>=endIndex) //如果没字符了,整个都是特殊字符,则直接返回 { return; }
           //接下来就是解析QueryString的过程了,比较繁琐,具体就是查找=和&符号,并截取中间的字符串作为key和value
    for (int i = startIndex; i <= endIndex; i++) { var c = url[i]; if (c == '=') { if (lastKeyword=='=') //处理 ?s==0 { startIndex=i+1; continue; } keyword = url.Substring(startIndex, i - startIndex); lastKeyword = c; startIndex = i+1; //startIndex++; } if (c == '&') { if (url[i-1] == '&') //处理 ?s=0&& 的情况 { startIndex = i + 1; continue; } if (lastKeyword=='=' || lastKeyword=='') // 处理 ?ss=0 的情况 { value = url.Substring(startIndex , i-startIndex); } // 处理 ?ddd& 或者 ?p=0&ddd 这种情况,切分出来的,算key else if (lastKeyword=='&' || lastKeyword =='') { keyword = url.Substring(startIndex, i - startIndex); value = string.Empty; } lastKeyword = ''; startIndex = i + 1; if (!string.IsNullOrEmpty(keyword)) { AddQuery(keyword, value); //添加入列表 } } } //如果还有剩余的字符,则处理完剩下的字符串 if (startIndex <= endIndex) { if (lastKeyword=='=' && !string.IsNullOrEmpty(keyword)) //处理 ?d=value 的情况 { value = url.Substring(startIndex,endIndex - startIndex); } else if ((lastKeyword == '=' && string.IsNullOrEmpty(keyword)) || lastKeyword == '&' || lastKeyword == '') { keyword = url.Substring(startIndex, endIndex+1 - startIndex); value = string.Empty; } AddQuery(keyword, value); } } }

    2.增加几个处理函数

        /// <summary>
        /// 添加一对参数值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public UrlModifier AddQuery(string key, string value)
        {
            //如果存在相同的Key的,则直接附加到原有值的后面
            var index = _queryKeys.IndexOf(x => x.key.CompareTo(key, true));
    
            if (index>0)
            {
                var orgValue = _queryKeys[index].value;
                _queryKeys[index] = (key, $"{orgValue},{value}");
            }
            else
            {
                _queryKeys.Add((key, value));
            }
    
            return this;
        }
    
        /// <summary>
        /// 添加一个keyvalue
        /// </summary>
        /// <param name="pair"></param>
        /// <returns></returns>
        public UrlModifier AddQuery((string key, string value) pair)
        {
            return AddQuery(pair.key, pair.value);
        }
    
        /// <summary>
        /// 删除指定key的项目
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public UrlModifier RemoveQuery(string key)
        {
            _queryKeys.Remove(x => x.key == key);
    
            return this;
        }
    
        /// <summary>
        /// 替换指定key的数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public UrlModifier ReplaceQuery(string key, string value)
        {
            var index = _queryKeys.IndexOf(x => x.key == key);
    
            if (index < 0)
            {
                _queryKeys.Add((key, value));
            }
            else
            {
                _queryKeys[index] = (key, value);
            }
    
            return this;
        }
    
        /// <summary>
        /// 设置锚点值
        /// </summary>
        /// <param name="anchor"></param>
        /// <returns></returns>
        public UrlModifier SetAnchor(string anchor)
        {
            _anchor = anchor;
            return this;
        }
    View Code

    3.重载ToString函数,用于拼接并输出操作后的结果

      public override string ToString()
        {
            var sb=new StringBuilder(60);
    
            if (!string.IsNullOrEmpty(_hostAndPath))
            {
                sb.Append(_hostAndPath);
            }
    
            if (_queryKeys!=null && _queryKeys.Count>0)
            {
                sb.Append('?');
    
                foreach (var item in _queryKeys)
                {
                    sb.Append(item.key);
    
                    if (!string.IsNullOrEmpty(item.value))
                    {
                        sb.Append('=');
                        sb.Append(item.value);
                        
                    }
                    sb.Append('&');
                }
    
                if (sb[sb.Length-1]=='&')
                {
                    sb.Remove(sb.Length - 1, 1);
                }
                
            }
    
            if (!string.IsNullOrEmpty(_anchor))
            {
                sb.Append('#');
                sb.Append(_anchor);
            }
    
            return sb.ToString();
        }

    4.当然,为了能节省解析的次数,毕竟如果是循环内修改参数的,那么基本上基础的url是相同的,因此,我们可以实现一个Clone,让解析的结果可以作为模板复用

        public UrlModifier Clone()
        {
            var item=new UrlModifier("") ;
    
            item._queryKeys.AddRange(this._queryKeys);
            item._hostAndPath = this._hostAndPath;
            item._anchor = this._anchor;
    
            return item;
        }

    5.为了方便开发,其实还可以再增加一些扩展函数,比如直接从Url的string转为URLModifier,或者增加不同的隐式转换的函数,具体可参考文章最后的源码文件

    6.调用测试:

        public void TestUrlModifier()
        {
            var url = "https://www.xxx.com/doc/base/infrastructure.html";
            var newUrl = url.ToUrlModifier().SetAnchor("topoop").RemoveQuery("keyword").ReplaceQuery("pppp", "iii")
                .AddQuery("o1", "ooo");
            var newUrlStr = newUrl.ToString();
    
            var test5 = "https://www.xxx.com/doc/base/infrastructure.html?=&o==ppp&&pppp=iii&o1=ooo&test2=&u#topoop"; //出现连续两个=号及连续的&号
            var newUrl5 = test5.ToUrlModifier();
            var newStr5 = newUrl5.ToString();
    
            var test6 = "/doc/base/infrastructure.html?=&o==ppp&&pppp=iii&o1=ooo&test2=&u#topoop"; //出现连续两个=号及连续的&号,并且是相对路径
            var newUrl6 = test6.ToUrlModifier();
            var newStr6 = newUrl6.ToString();
        }

    输出的结果为:

    newUrlStr:  https://www.xxx.com/doc/base/infrastructure.html?pppp=iii&o1=ooo#topoop

    newStr5: https://www.xxx.com/doc/base/infrastructure.html?o=ppp&pppp=iii&o1=ooo&test2&u#topoop   //排除掉错误的格式,并格式化输出

    newStr6: /doc/base/infrastructure.html?o=ppp&pppp=iii&o1=ooo&test2&u#topoop     //输出原始的相对路径 并排除错误格式

    注意:该类并不会对QueryString中的Key或者Value进行编码,因此,有需要编码的,可增加一个AddQuery的重载,进行处理

    完整的类的代码在:https://github.com/kugarliyifan/Kugar.Core/blob/master/Kugar.Core.NetCore/Network/UrlModifier.cs 稍作修改就可以单独使用

    AddQuery函数中使用到了一个IndexOf的扩展方法,在:https://github.com/kugarliyifan/Kugar.Core/blob/master/Kugar.Core/ExtMethod/ListExtMethod.cs#L1193 

  • 相关阅读:
    windows 7下matlab R2010a输入乱码的解决方案
    用 Microsoft Visual C++ 创建一个使用 wpcap.dll 的应用程序,
    E: oss4dkms: 子进程 脚本出错postinstallation 安装升级更新时出错的解决方法
    关于linux下面挂载Windows硬盘,但是无法在Windows下看到数据
    如何读取多个文件,文件后缀名不一致,不过类似source.1 source.2 source.3等
    Fedora 12 13 14基础环境配置
    linux内核空间与用户空间信息交互方法
    HDU 1232 畅通工程(最小生成树+并查集)
    hdu 2647 Reward(拓扑排序,反着来)
    HDU 1532 Drainage Ditches (最大网络流)
  • 原文地址:https://www.cnblogs.com/kugar/p/12381370.html
Copyright © 2020-2023  润新知