• 搞定queryString


    querystring字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析。querystring模块只提供4个方法:

    • querystring.parse
    • querystring.stringify
    • querystring.escape
    • querystring.unescape

    这4个方法是相对应的。

    首先,使用querystring模块之前,需要require进来:

    const querystring = require("querystring");

    其次,就可以使用模块下的方法了:

    1 querystring.parse(str,separator,eq,options)

    parse这个方法是将一个字符串反序列化为一个对象。

    参数:

    • str指需要反序列化的字符串;
    • separator(可省)指用于分割str这个字符串的字符或字符串,默认值为"&";
    • eq(可省)指用于划分键和值的字符或字符串,默认值为"=";
    • options(可省)该参数是一个对象,里面可设置maxKeys和decodeURIComponent这两个属性:
    1. maxKeys:传入一个number类型,指定解析键值对的最大值,默认值为1000,如果设置为0时,则取消解析的数量限制;
    2. decodeURIComponent:传入一个function,用于对含有%的字符串进行解码,默认值为querystring.unescape。在官方API的例子中,使用gbkDecodeURIComponent这个方法会报错,显示gbkDecodeURIComponent is no defined,这是因为在使用这个gbkDecodeURIComponent这个方法之前需要先进行定义。在API中也写了Assuming gbkDecodeURIComponent function already exists...这句话的意思是”假设这个gbkDecodeURIComponent方法已经存在”。

    例子1,querystring.parse

     1 querystring.parse("name=whitemu&sex=man&sex=women");
     2 /*
     3 return:
     4 { name: 'whitemu', sex: [ 'man', 'women' ] }
     5 */
     6 querystring.parse("name=whitemu#sex=man#sex=women","#",null,{maxKeys:2});
     7 /*
     8 return:
     9 { name: 'whitemu', sex: 'man' }
    10 */

    2 querystring.stringify(obj,separator,eq,options)

    stringify这个方法是将一个对象序列化成一个字符串,与querystring.parse相对。

    参数:

    • obj指需要序列化的对象
    • separator(可省)用于连接键值对的字符或字符串,默认值为"&";
    • eq(可省)用于连接键和值的字符或字符串,默认值为"=";
    • options(可省)传入一个对象,该对象可设置encodeURIComponent这个属性:

    encodeURIComponent:值的类型为function,可以将一个不安全的url字符串转换成百分比的形式,默认值为querystring.escape()。

    例子2,querystring.stringify

    querystring.stringify({name: 'whitemu', sex: [ 'man', 'women' ] });
    /*
    return:
    'name=whitemu&sex=man&sex=women'
    */
    querystring.stringify({name: 'whitemu', sex: [ 'man', 'women' ] },"*","$");
    /*
    return:
    'name$whitemu*sex$man*sex$women'
    */

    3 querystring.escape(str)

    escape可使传入的字符串进行编码

    例子3,querystring.escape

    querystring.escape("name=慕白");
    /*
    return:
    'name%3D%E6%85%95%E7%99%BD'
    */

    4 querystring.unescape(str)

    unescape方法可将含有%的字符串进行解码

    例子4,querystring.unescape

    querystring.unescape('name%3D%E6%85%95%E7%99%BD');
    /*
    return:
    'name=慕白'
    */

    小结:

    querystring这个模块相对的还是比较简单,仅有4个方法。

    • querystring.stringify序列化;
    • querystring.parse反序列化;
    • querystring.escape编码;
    • querystring.unescape解码;

    进阶版

    可以写一个函数,专门用于做转换

     private object ConvertParameter(string name, object defaultValue, bool isRequired)

    我们甚至还可以把它抽象出来一个方法。

    提取抽象方法

    用Attribute和反射的思想,首先给变量设置HttpQueryString的属性,绑定上相应的QueryString,然后由Page基类来读取相应的QueryString信息。

    属性这么写(HttpQueryStringAttribute.cs):

    [AttributeUsage(AttributeTargets.Field)] 
        
        public sealed class HttpQueryStringAttribute : Attribute { 
            private string _name; 
            private object _defaultValue; 
            private bool _isRequired; 
            
            
        public HttpQueryStringAttribute(string name) { 
                _name = name; 
                _defaultValue = null; 
                _isRequired = true; 
            }    
            
        public HttpQueryStringAttribute(string name, object defaultValue) { 
                _name = name; 
                _defaultValue = defaultValue; 
                _isRequired = false; 
            } 
        
        public string Name { 
                get { return _name; } 
            } 
            
        public object DefaultValue { 
                get { return _defaultValue; } 
            }
            
        public bool IsRequired 
            { 
                get { return _isRequired; } 
            } 
        } 

    页面基类是这样的(PageBase.cs):

    public class PageBase : Page 
        {
         protected override void OnLoad(System.EventArgs e) { 
                ParameterInitialize(); 
                base.OnLoad(e); 
            } 
        
        
        private void ParameterInitialize() { 
            Type type = this.GetType(); 
        
            FieldInfo[] fields = type.GetFields(); 
    
                foreach (FieldInfo field in fields) 
                {
                    HttpQueryStringAttribute attribute = (HttpQueryStringAttribute)Attribute.GetCustomAttribute(field, typeof(HttpQueryStringAttribute)); 
    
                    if (attribute != null) 
                    { 
                        SetField(field, attribute); 
                    } 
                } 
            }
            
        private void SetField(FieldInfo field, HttpQueryStringAttribute attribute) 
            {
                if (attribute.IsRequired) 
                { 
                    if (Request.QueryString[attribute.Name] != null) 
                    { 
                        SetFieldValue(field, this, attribute.Name, field.FieldType); 
                    } 
                    else 
                    { 
                        throw new Exception(string.Format("Query string /"{0}/" is required", attribute.Name), new NullReferenceException()); 
                    } 
                } 
                else 
                { 
                    if (attribute.DefaultValue == null || field.FieldType == attribute.DefaultValue.GetType()) 
                    { 
                        if (Request.QueryString[attribute.Name] == null || Request.QueryString[attribute.Name] == string.Empty) 
                        { 
                            field.SetValue(this, attribute.DefaultValue); 
                        } 
                        else 
                        { 
                            SetFieldValue(field, this, attribute.Name, field.FieldType); 
                        } 
                    } 
                    else 
                    { 
                        throw new Exception(string.Format("Invalid default value of query string /"{0}/"({1})", attribute.Name, field.Name), new NullReferenceException()); 
                    } 
                } 
            }
            
        private void SetFieldValue(FieldInfo field, object obj, string name, Type conversionType) { 
                try 
                { 
                    field.SetValue(obj, Convert.ChangeType(Request.QueryString[name], conversionType)); 
                } 
                catch (Exception ex) 
                { 
                    throw new Exception(string.Format("The given value of query string /"{0}/" can not be convert to {1}", name, conversionType), ex); 
                } 
            } 
        } 

    在页面里,这样写就OK了(Default.aspx.cs):

    public partial class _Default : PageBase 
    { 
        [HttpQueryString("Name", "Anonymous")] 
        public string name; 
        
         [HttpQueryString("UserId")] 
        public int userId; 
    
        protected void Page_Load(object sender, EventArgs e) 
        { 
            Response.Write(string.Format("Name is {0}<br/>", name)); 
            Response.Write(string.Format("UserId is {0}<br/>", userId)); 
        } 
    } 

    讨论

    根据定义的变量的数据类型自动转换对应的QueryString,可以省去以后在页面里处理Query String的代码。

    反过来想,QueryString 的处理没必要上升到反射的高度,复杂的实现也许会丧失一定的灵活性。比如我某个值忽然要改为从 Form 里面得到呢?从 Session 得到呢?这时候就可以比较出哪种做法更适合敏捷的适应需求。

    页面里的 QueryString 的处理,之所以大家都很痛恨手工写编码,无非是因为这么几点:

    1. 需要判断是否 == null 才敢用 .ToString(), 很不爽。稍微不注意,就会抛出异常导致页面错误。
    2. 整形,double 等值类型从 QueryString 里面获取的时候,不知道是否为合法的数值,因此 Parse 的时候总是要写重复的处理异常的代码。
  • 相关阅读:
    zookeeper笔记整理(二)
    zookeeper笔记整理(一)
    SpringBoot源码分析(三)整合MyBatis
    四、MyBatis终结篇(补充中...)
    三、SpringMVC终结篇(补充中...)
    二、SpringAOP终结篇(补充中...)
    一、SpringIOC终结篇(补充中...)
    跳出初学MySQL知识的原理整理(一)
    SpringBoot源码分析(二)启动原理
    一文带你学会基于SpringAop实现操作日志的记录
  • 原文地址:https://www.cnblogs.com/yizhiamumu/p/9046017.html
Copyright © 2020-2023  润新知