首页 > 代码库 > Redis编码问题

Redis编码问题

 

       最近搞redis存储对象出了点问题,大概说一下背景,项目原有的东东以前存的是redis,存储的直接是对象模型,没有问题,这里存储对象存储任何信息事都没有问题的。但是现在调整为存储序列化的json字符串,此时获取对象信息发生了问题,不是报错就是有乱码似的东东,一开始以为是编码问题,其实不准确,现在来一步步看一看到底是什么问题(这里的测试只是为了简单,命名等都不规范,大家凑活着看了解问题就行)

    

public class test    {        public string Name { get; set; }        public string View { get; set; }         public IList<AAA> list { get; set; }    }     public class AAA    {        public string Name { get; set; }        public string View { get; set; }    }     public class CartController : Controller    {        public void Index2()        {            test tes = new test();            tes.Name = "z中文";            tes.View = null;            tes.list = new List<AAA>();            AAA d = new AAA();            d.Name = "123";            d.View = "asd";            AAA b = new AAA();            b.Name = "我是特殊符号~!^?*$#<>\\";            b.View = "我是单引号\"";            tes.list.Add(d);            tes.list.Add(b);            //var aa = Newtonsoft.Json.JsonConvert.SerializeObject(tes);            RedisManager.Execute(redis => redis.Set("test", tes));            var ggg = RedisManager.Execute(redis => redis.Get<test>("test"));        }    }

 

 

 直接存储对象是没有问题的,看看其中的set和get吧,

    

public bool Set<T>(string key, T value)    {      byte[] numArray = (object) value as byte[];      if (numArray != null)      {        base.Set(key, numArray);        return true;      }      else      {        string str = JsonSerializer.SerializeToString<T>(value);        this.SetEntry(key, str);        return true;      }}     public static string SerializeToString<T>(T value)    {      if ((object) value =http://www.mamicode.com/= null)>

恩恩,看样子应该是,存储的时候序列化了,并且使用utf8编码,那好吧,get肯定也就是utf8编码反序列化成对象取出来的,所以泛型的存取数据并没有跟编码有什么关系,那问题出在哪里呢。

    

public T Get<T>(string key)    {      if (!(typeof (T) == typeof (byte[])))        return JsonSerializer.DeserializeFromString<T>(this.GetValue(key));      else        return (T) base.Get(key);    }public byte[] Get(string key)    {      return this.GetBytes(key);    } public byte[] GetBytes(string key)    {      if (key == null)        throw new ArgumentNullException("key");      return this.SendExpectData(Commands.Get, StringExtensions.ToUtf8Bytes(key));    }

上面代码解释了为什么,对象怎么存储都没有问题,再来看看string类型的信息。

public void Index2()        {            test tes = new test();            tes.Name = "z中文";            tes.View = null;            tes.list = new List<AAA>();            AAA d = new AAA();            d.Name = "123";            d.View = "asd";            AAA b = new AAA();            //b.Name = "我是特殊符号~!^?*$#<>\\";            b.Name = "2";            //b.View = "\"";            b.View = "\\";            tes.list.Add(d);            tes.list.Add(b);             var aa = Newtonsoft.Json.JsonConvert.SerializeObject(tes);            RedisManager.Execute(redis => redis.Set("niutaotao_cart", aa));                       var ggg = RedisManager.Execute(redis => redis.Get<byte[]>("niutaotao_cart"));            var ii = RedisManager.Execute(redis => redis.Get<string>("niutaotao_cart"));             var json="{\"Name\":\"z中文\",\"View\":null,\"list\":[{\"Name\":\"123\",\"View\":\"asd\"},{\"Name\":\"2\",\"View\":\"\\\"}]}";            RedisManager.Execute(redis => redis.Set("ddd", json));            var o = RedisManager.Execute(redis => redis.Get<byte[]>("ddd"));            var pp = RedisManager.Execute(redis => redis.Get<string>("ddd"));        }

可以看看监视的结果,不多说直接上图。大概能看出点区别了。

  

 问题来了,1.json编码后首先转移符并没有特殊处理,而是直接写进了json格式字符串中

    2. 重现向上看取数据的时候 1.双引号有问题 ,貌似都变为了转移符+双引号

                 2.转移符有问题,具体规律也看不大出来,貌似就是之前都加了两个转移符

                 3。中文编码也有问题(这尼玛很奇怪啊,从上面代码来看,应该跟编码没关系才对)

我们继续看代码,看看set存储数据的时候有什么特别的地方。我们可以看到对象和字符串的处理是不同的,嗯,估计问题就应该在这里了,看代码。

{"Name":"z中文","View":null,"list":[{"Name":"123","View":"asd"},{"Name":"2","View":"\\"}]} public static void WriteString(TextWriter writer, string value)    {      if (value =http://www.mamicode.com/= null)"null");      else if (!JsonUtils.HasAnyEscapeChars(value))      {        writer.Write(‘"‘);        writer.Write(value);        writer.Write(‘"‘);      }      else      {        char[] chArray = new char[4];        writer.Write(‘"‘);        int length = value.Length;        for (int index = 0; index < length; ++index)        {          switch (value[index])          {            case ‘\b‘:              writer.Write("\\b");              break;            case ‘\t‘:              writer.Write("\\t");              break;            case ‘\n‘:              writer.Write("\\n");              break;            case ‘\f‘:              writer.Write("\\f");              break;            case ‘\r‘:              writer.Write("\\r");              break;            case ‘"‘:            case ‘\\‘:              writer.Write(‘\\‘);              writer.Write(value[index]);              break;            default:              if ((int) value[index] >= 32 && (int) value[index] <= 126)              {                writer.Write(value[index]);                break;              }              else if ((int) value[index] < 55296 || (int) value[index] > 57343)              {                JsonUtils.IntToHex((int) value[index], chArray);                writer.Write("\\u");                writer.Write(chArray);                break;              }              else                break;          }        }        writer.Write(‘"‘);      }    }

  

好了基本上找到原因了,问题就出在方法中列出的”\,””等特殊符号的问题,而且看((int) value[index] < 55296 || (int) value[index] > 57343)句话应该是对这个范围之外的符号进行了转码,具体什么转码方式小弟不清楚,

所以呢,解决办法就来了,我们是不是可以在存储之前将这些被视为特殊符号,特殊处理的字符进行处理呢,然后区出来之后再解码是不是就可以了。

好了试一把。我们就用UrlEncode试一下吧

System.Web.HttpUtility.UrlEncode( ““, Encoding.UTF8);System.Web.HttpUtility. UrlDecode ( ““, Encoding.UTF8); var aa = Newtonsoft.Json.JsonConvert.SerializeObject(tes);            var jj = System.Web.HttpUtility.UrlEncode(aa, Encoding.UTF8);            RedisManager.Execute(redis => redis.Set("niutaotao_cart", jj));                       var ggg = RedisManager.Execute(redis => redis.Get<byte[]>("niutaotao_cart"));            var ii = RedisManager.Execute(redis => redis.Get<string>("niutaotao_cart"));            var zz = System.Web.HttpUtility.UrlDecode(ii,Encoding.UTF8);

  

看看结果

 

 

呵呵,尼玛可以了。这里解决问题就可以了,关于redis的存储结构和实现,可以学习下下面两篇文章。

关于redis的存储结构大家可以看看(http://www.cnblogs.com/shanyou/archive/2012/09/04/2670972.html)

关于redis的实现可以看看(http://www.searchtb.com/2011/05/redis-storage.html)

redis官网(http://www.redis.cn/)