Redis編碼問題

來源:互聯網
上載者:User

標籤:des   blog   http   使用   資料   os   

 

       最近搞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 == null)        return (string) null;      if (typeof (T) == typeof (object) || typeof (T).IsAbstract || typeof (T).IsInterface)      {        if (typeof (T).IsAbstract || typeof (T).IsInterface)          JsState.IsWritingDynamic = true;        string str = JsonSerializer.SerializeToString((object) value, value.GetType());        if (typeof (T).IsAbstract || typeof (T).IsInterface)          JsState.IsWritingDynamic = false;        return str;      }      else      {        StringBuilder sb = new StringBuilder();        using (StringWriter stringWriter = new StringWriter(sb, (IFormatProvider) CultureInfo.InvariantCulture))        {          if (typeof (T) == typeof (string))            JsonUtils.WriteString((TextWriter) stringWriter, (object) value as string);          else            JsonWriter<T>.WriteObject((TextWriter) stringWriter, (object) value);        }        return ((object) sb).ToString();      }    }     public void SetEntry(string key, string value)    {      byte[] numArray = value != null ? ServiceStack.Text.StringExtensions.ToUtf8Bytes(value) : (byte[]) null;      this.Set<byte[]>(key, numArray);}  

恩恩,看樣子應該是,儲存的時候序列化了,並且使用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 == null)        writer.Write("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/)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.