(转)细说Cookie

原文地址:

http://www.cnblogs.com/fish-li/archive/2011/07/03/2096903.html

 

 

Cookie虽然是个很简单的东西,但它又是WEB开发中一个很重要的客户端数据来源,而且它可以实现扩展性很好的会话状态, 所以我认为每个WEB开发人员都有必要对它有个清晰的认识。本文将对Cookie这个话题做一个全面的描述, 也算是本人对Cookie的认识总结。

Cookie 概述

Cookie是什么? Cookie 是一小段文本信息,伴随着用户请求和页面在 Web 服务器和浏览器之间传递。Cookie 包含每次用户访问站点时 Web 应用程序都可以读取的信息。

为什么需要Cookie? 因为HTTP协议是无状态的,对于一个浏览器发出的多次请求,WEB服务器无法区分 是不是来源于同一个浏览器。所以,需要额外的数据用于维护会话。Cookie 正是这样的一段随HTTP请求一起被传递的额外数据。

Cookie能做什么? Cookie只是一段文本,所以它只能保存字符串。而且浏览器对它有大小限制以及 它会随着每次请求被发送到服务器,所以应该保证它不要太大。Cookie的内容也是明文保存的,有些浏览器提供界面修改,所以, 不适合保存重要的或者涉及隐私的内容。

Cookie 的限制。 大多数浏览器支持最大为 4096 字节的 Cookie。由于这限制了 Cookie 的大小,最好用 Cookie 来存储少量数据,或者存储用户 ID 之类的标识符。用户 ID 随后便可用于标识用户,以及从数据库或其他数据源中读取用户信息。 浏览器还限制站点可以在用户计算机上存储的 Cookie 的数量。大多数浏览器只允许每个站点存储 20 个 Cookie;如果试图存储更多 Cookie,则最旧的 Cookie 便会被丢弃。有些浏览器还会对它们将接受的来自所有站点的 Cookie 总数作出绝对限制,通常为 300 个。

通过前面的内容,我们了解到Cookie是用于维持服务端会话状态的,通常由服务端写入,在后续请求中,供服务端读取。 下面本文将按这个过程看看Cookie是如何从服务端写入,最后如何传到服务端以及如何读取的。

Cookie的写、读过程

在Asp.net中,读写Cookie是通过使用HttpCookie类来完成的,它的定义如下:

public sealed class HttpCookie
{// 获取或设置将此 Cookie 与其关联的域。默认值为当前域。public string Domain { get; set; }// 获取或设置此 Cookie 的过期日期和时间(在客户端)。public DateTime Expires { get; set; }// 获取一个值,通过该值指示 Cookie 是否具有子键。public bool HasKeys { get; }// 获取或设置一个值,该值指定 Cookie 是否可通过客户端脚本访问。// 如果 Cookie 具有 HttpOnly 属性且不能通过客户端脚本访问,则为 true;否则为 false。默认为 false。public bool HttpOnly { get; set; }// 获取或设置 Cookie 的名称。public string Name { get; set; }// 获取或设置要与当前 Cookie 一起传输的虚拟路径。默认值为当前请求的路径。public string Path { get; set; }// 获取或设置一个值,该值指示是否使用安全套接字层 (SSL)(即仅通过 HTTPS)传输 Cookie。public bool Secure { get; set; }// 获取或设置单个 Cookie 值。默认值为空引用。public string Value { get; set; }// 获取单个 Cookie 对象所包含的键值对的集合。public NameValueCollection Values { get; }// 获取 System.Web.HttpCookie.Values 属性的快捷方式。public string this[string key] { get; set; }
}

Cookie写入浏览器的过程:我们可以使用如下代码在Asp.net项目中写一个Cookie 并发送到客户端的浏览器(为了简单我没有设置其它属性)。

HttpCookie cookie = new HttpCookie("MyCookieName", "string value");
Response.Cookies.Add(cookie);

我想很多人都写过类似的代码,但是,大家有没有想过:Cookie最后是如何发送到客户端的呢?我们打开Fiddler来看一下吧。

从上图,您应该能发现,我们在服务端写的Cookie,最后其实是通过HTTP的响应头这种途径发送到客户端的。每一个写入动作, 都会产生一个【Set-Cookie】的响应头。
浏览器正是在每次获取请求的响应后,检查这些头来接收Cookie的。

Asp.net获取Cookie的过程:我们可以使用如下代码在Asp.net项目中读取一个Cookie

HttpCookie cookie = Request.Cookies["MyCookieName"];
if( cookie != null )labCookie1.Text = cookie.Value;
elselabCookie1.Text = "未定义";

代码同样也很简单,还是类似的问题:大家有没有想过,Cookie是如何传到服务端的呢?我们还是继续使用Fiddler来寻找答案吧。

从图片中,我们可以发现,Cookie是放在请求头中,发送到服务端的。如果你一直刷新页面,就能发现,每次HTTP请求,Cookie都会被发送。当然了,浏览器也不是发送它所接收到的所有Cookie,它会检查当前要请求的域名以及目录, 只要这二项目与Cookie对应的Domain和Path匹配,才会发送。对于Domain则是按照尾部匹配的原则进行的。
所以,我在访问 www.cnblogs.com 时,浏览器并不会将我在浏览 www.163.com 所接收到的 Cookie 发出去。

删除Cookie:其实就是在写Cookie时,设置Expires为一个【早于现在时间的时间】。也就是:设置此Cookie已经过期, 浏览器接收到这个Cookie时,便会删除它们。

HttpCookie cookie = new HttpCookie("MyCookieName", null);
cookie.Expires = new DateTime(1900, 1, 1);
Response.Cookies.Add(cookie);

使用Cookie保存复杂对象

前面的示例代码大致演示了Cookie的读写操作。不过,我们平时可能希望将更复杂的【自定义类型】通过Cookie来保存, 那么又该如何操作呢?对于这个问题,我们定义一个类型来看看如何处理。

public class DisplaySettings 
{public int Style;public int Size;public override string ToString(){return string.Format("Style = {0}, Size = {1}", this.Style, this.Size);}    
}

上面的代码,我定义一个类型,用于保存用户在浏览页面时的显示设置。接下来,我将介绍二种方法在Cookie中保存并读取它们。

方法-1,经典做法。(注意前面给出的HttpCookie定义代码中的最后二个成员)

private void WriteCookie_2a()
{DisplaySettings setting = new DisplaySettings { Style = 1, Size = 24 };HttpCookie cookie = new HttpCookie("DisplaySettings1");cookie["Style"] = setting.Style.ToString();cookie["Size"] = setting.Size.ToString();Response.Cookies.Add(cookie);
}private void ReadCookie_2a()
{HttpCookie cookie = Request.Cookies["DisplaySettings1"];if( cookie == null )labDisplaySettings1.Text = "未定义";else {DisplaySettings setting = new DisplaySettings();setting.Style = cookie["Style"].TryToInt();setting.Size = cookie["Size"].TryToInt();labDisplaySettings1.Text = setting.ToString();}
}

方法-2,将对象JSON序列化为字符串。

private void WriteCookie_2b()
{DisplaySettings setting = new DisplaySettings { Style = 2, Size = 48 };HttpCookie cookie = new HttpCookie("DisplaySettings2", setting.ToJson());Response.Cookies.Add(cookie);
}private void ReadCookie_2b()
{HttpCookie cookie = Request.Cookies["DisplaySettings2"];if( cookie == null )labDisplaySettings2.Text = "未定义";else {DisplaySettings setting = cookie.Value.FromJson<DisplaySettings>();labDisplaySettings2.Text = setting.ToString();}
}

这段代码使用了我定义的二个扩展方法。点击此处展开

/// <summary>
/// 将一个对象序列化成 JSON 格式字符串
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToJson(this object obj)
{if( obj == null )return string.Empty;JavaScriptSerializer jss = new JavaScriptSerializer();return jss.Serialize(obj);
}/// <summary>
/// 从JSON字符串中反序列化对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="cookie"></param>
/// <returns></returns>
public static T FromJson<T>(this string cookie)
{if( string.IsNullOrEmpty(cookie) )return default(T);JavaScriptSerializer jss = new JavaScriptSerializer();return jss.Deserialize<T>(cookie);
}

对于这二种方法,我个人更喜欢后者,因为它具有更好扩展性:如果类型增加了成员,不需要修改读写Cookie的代码。
不过,这种方式产生的有些字符,比如【双引号】,极少数浏览器(Opera)不支持,所以需要做UrlEncode或者Base64编码处理。
同理,对于第一种方法,遇到Value有【双引号】时,我们同样需要做UrlEncode或者Base64编码处理。

Js中读写Cookie

Cookie并非只能在服务端读写,在客户端的浏览器中也可以实现对它的读写访问。而且在JS中创建的Cookie对于服务端仍然有效(可见), 接下来我们来看看在JS中如何写入Cookie,演示代码将创建一个按钮,并在点击按钮后写入Cookie

<input type="button" onclick="WriteCookie();" value="WriteCookie" /><script type="text/javascript">function WriteCookie() {var cookie = "cookie_js=22222222; path=/";document.cookie = cookie;}    
</script>

在JS中写Cookie很简单,只要给document.cookie赋值一个Cookie字符串即可,至于格式,可以参考前面用Fiddle看到的结果。

再来看一下如何使用JS读取Cookie吧。请参考如下代码:

<input type="button" onclick="ReadCookie();" value="ReadCookie" /><script type="text/javascript">function ReadCookie() {alert(document.cookie);}    
</script>

仍然是访问document.cookie,不过,这次我们得到却是全部的Cookie值,每个Key/Value项用分号分开,中间则用等号分开。 所以, 如果您想在JS中读取Cookie,一定要按照这个规则来拆分并解析您要读取的Cookie项。鉴于这样的操作有些繁琐, 我们可以jquery.cookie.js插件来轻松完成这个功能,有兴趣的朋友也可以看一下它是如何处理的。 这个插件的代码比较少,这里就直接贴出,点击此处展开

注意哦:前面我们看到了HttpCookie有个HttpOnly属性,如果它为true,那么JS是读不到那个Cookie的,也就是说: 我们如果在服务端生成的Cookie不希望在JS中能被访问,可以在写Cookie时,设置这个属性。不过,通过一些工具,还是可以看到它们。

接下来,我们再来看看Asp.net中Cookie有哪些应用。

Cookie在Session中的应用

在Asp.net中,HttpContext, Page对象都有个Session的对象,我们可以使用它来方便地在服务端保存一些与会话相关的信息。
前面我们也提到过,HTTP协议是无状态的,对于一个浏览器发出的多次请求,WEB服务器无法区分 是不是来源于同一个浏览器。所以,为了实现会话,服务端需要一个会话标识ID能保存到浏览器,让它在后续的请求时都带上这个会话标识ID,以便让服务端知道 某个请求属于哪个会话,这样便可以维护与会话相关的状态数据。由于Cookie对于用户来说,是个不可见的东西,而且每次请求都会传递到 服务端,所以它就是很理想的会话标识ID的保存容器。在Asp.net中,默认也就是使用Cookie来保存这个ID的。注意:虽然Asp.net 2.0也支持无Cookie的会话,但那种方式要修改URL,也有它的缺点,因此这种方法并没有广泛的使用。本文将不对这个话题做过多的分析, 就此略过无Cookie会话这种方式。

我们来看看Session是如何使用Cookie来保存会话标识ID的,在默认的Asp.net配置中,Web.config有着如下定义:

<sessionState mode="InProc" cookieName="ASP.NET_SessionId" cookieless="UseCookies"></sessionState>

如果我们执行以下操作:

Session["Key1"] = DateTime.Now;

此时,我们可以使用一些浏览器提供的工具来查看一下现在的Cookie情况。

从图片上看,这个Cookie的名字就是我们在配置文件中指出的名称,我们可以修改一下配置文件:

<sessionState cookieName="SK"></sessionState>

再来执行上面的写Session的操作,然后看Cookie

我们可以看到:SK的Cookie出现了。说明:在截图时我把名称为"ASP.NET_SessionId"的Cookie删除了。

通过上面示例,我们可以得到结论,Session的实现是与Cookie有关的,服务端需要将会话标识ID保存到Cookie中。
这里再一次申明,除非你使用无Cookie的会话模式,否则Session是需要Cookie的支持。反过来,Cookie并不需要Session的支持。

Cookie在身份验证中的应用

我想很多人都在Asp.net的开发中使用过Form身份认证。对于一个用户请求, 我们可以在服务端很方便地判断它是不是代表一个已登录用户。

this.labStatus.Text = (Request.IsAuthenticated ? "已登录" : "未登录");

那么,您有没有好奇过:Asp.net是如何识别一个请求是不是一个已登录用户发起的呢?说到这里,我们就要从用户登录说起了。 为了实现登录及Form认证方式,我们需要如下配置:

<authentication mode="Forms" ><forms name="UserStatus"></forms>
</authentication>

接下来,我们需要实现用户登录逻辑。具体实现方式有很多,不过,最终的调用都是差不多的,如下代码所示:

private void SetLogin()
{System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);
}

只要执行了以上代码,我们就可以看到,前面的判断【Request.IsAuthenticated】返回true,最终会显示"已登录"。 为了探寻这个秘密,我们还是来看一下当前页面的Cookie情况。

果然,多出来一个Cookie,名称与我在配置文件中指定的名称相同。我们再来看看如果注销当前登录会是什么样子的:

private void SetLogout()
{System.Web.Security.FormsAuthentication.SignOut();
}

看到了吗,名为"UserStatus"的Cookie不见了。此时如果你再去观察【Request.IsAuthenticated】,可以发现它此时返回 false。 或者,您也可以再试一次,登录后,直接删除名为"UserStatus"的Cookie,也能发现登录状态将显示"未登录"。 或许,您还是有点不清楚前面我调用【System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);】后,Asp.net做了些什么, 回答这个问题其实很简单:自己用Reflector.exe去看一下Asp.net的实现吧。
这里为了更让您能信服登录与Cookie有关,我将直接创建一个Cookie看一下Asp.net能不能认可我创建的Cookie,并认为登录有效。请看代码:

private void SetLogin()
{//System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);// 下面的代码和上面的代码在作用上是等效的。FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, "fish", DateTime.Now, DateTime.Now.AddDays(30d), false, string.Empty);string str = FormsAuthentication.Encrypt(ticket);HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, str);Response.Cookies.Add(cookie);
}

如果执行这段代码,您将发现:【Request.IsAuthenticated】返回true,登录状态会显示"已登录"。
至此,我们可以得出一个结论:Form身份认证依赖Cookie,Asp.net就是每次检查我们在配置文件中指定的Cookie名称,并解密这个Cookie来判断当前请求用户的登录状态。

Cookie的安全状况

从以上图片,您应该能发现:浏览器能提供一些界面让用户清楚的观察我们在服务端写的Cookie, 甚至有些浏览器还提供很方便的修改功能。如下图所示:

所以,我们在服务端写代码读取Cookie时,尤其是涉及类型转换、反序列化或者解密时,一定要注意这些操作都有可能会失败。 而且上图也清楚的反映了一个事实:Cookie中的值都是“一目了然”的,任何人都能看到它们。所以,我们尽量不要直接在Cookie中 保存一些重要的或者敏感的内容。如果我们确实需要使用Cookie保存一些重要的内容,但又不希望被他人看懂, 我们可以使用一些加密的方法来保护这些内容。

1. 对于一些重要性不高的内容,我们可以使用Base64之类的简单处理方式来处理。

2. 对于重要性相对高一点的内容,我们可以利用.net提供的一些加密工具类,自己来设计加密方法来保护。不过, 密码学与加密解密并不是很简单的算法,因此,自己设计的加密方式可能不会很安全。

3. 重要的内容,我们可以使用.net提供的FormsAuthenticationTicket,FormsAuthentication来加密。我认为这种方式还是比较安全的。 毕竟前面我们也看过了,Asp.net的Form身份认证就是使用这种方式来加密用户登录的身份标识的,所以,如果这种方式不安全, 也就意味着Asp.net的身份认证也不安全了。 如果您使用这种方式来加密,那么请注意:它产生的加密后文本还是比较大的, 前面我也提到过,每次请求时,浏览器都会带上与请求相匹配的所有Cookie,因此,这种Cookie会对传输性能产生一定的影响, 所以,请小心使用,切记不可过多的使用。

这里要补充一下:去年曾经出现过【Padding Oracle Attack】这个话题, 一些人甚至错误的认为是Asp.net加密方式不安全!如果您也是这样认为的,那么可以看一下这篇文章:浅谈这次ASP.NET的Padding Oracle Attack相关内容,以消除这个错误的认识。当然了,我们也可以从这个话题得到一些收获:解密失败时,不要给出过多的提示,就当没有这个Cookie存在。

如何在C#发请的请求中使用Cookie

前面我们一直在谈服务端与浏览器中使用Cookie,其实浏览器也是一个普通的应用程序,.net framework也提供一些类也能让我们 直接发起HTTP请求,下面我们来看一下如何在C#发请的请求中使用Cookie ,其实也很简单,主要是使用了CookieContainer类,请看以下演示代码:

private static string SendHttpRequestGet(string url, Encoding encoding, CookieContainer cookieContainer){if( string.IsNullOrEmpty(url) )throw new ArgumentNullException("url");if( encoding == null )throw new ArgumentNullException("encoding");HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);request.Method = "GET";request.CookieContainer = cookieContainer;using( WebResponse response = request.GetResponse() ) {using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) {return reader.ReadToEnd();}}}private void SendHttpDEMO(){StringBuilder sb = new StringBuilder();CookieContainer cookieContainer = new CookieContainer();string url = "http://www.taobao.com";SendHttpRequestGet(url, Encoding.Default, cookieContainer);// 后面可以继续发起HTTP请求,此时将会包含上次从服务器写入的Cookie//SendHttpRequestGet("同域名下的其它URL", Encoding.Default, cookieContainer);// 至此,我们可以显示取得了哪些CookieCookieCollection cookies = cookieContainer.GetCookies(new Uri(url));if( cookies != null ) {foreach( System.Net.Cookie cookie in cookies )sb.AppendLine(cookie.ToString());}txtCookies.Text = sb.ToString();}

重构与使用总结

在前面的Asp.net示例代码中,我一直使用.net提供的HttpCookie类来操作Cookie,是为了展示用原始的方式来使用Cookie, 这些代码有点重复,也有点繁琐, 为此,我提供了几个简单的方法可以更容易的使用Cookie,也算是对Cookie使用的一个总结。

/// <summary>
/// 用于方便使用Cookie的扩展工具类
/// </summary>
public static class CookieExtension
{// 我们可以为一些使用频率高的类型写专门的【读取】方法/// <summary>/// 从一个Cookie中读取字符串值。/// </summary>/// <param name="cookie"></param>/// <returns></returns>public static string GetString(this HttpCookie cookie){if( cookie == null )return null;return cookie.Value;}/// <summary>/// 从一个Cookie中读取 Int 值。/// </summary>/// <param name="cookie"></param>/// <param name="defaultVal"></param>/// <returns></returns>public static int ToInt(this HttpCookie cookie, int defaultVal){if( cookie == null )return defaultVal;return cookie.Value.TryToInt(defaultVal);}/// <summary>/// 从一个Cookie中读取值并转成指定的类型/// </summary>/// <typeparam name="T"></typeparam>/// <param name="cookie"></param>/// <returns></returns>public static T ConverTo<T>(this HttpCookie cookie){if( cookie == null )return default(T);return (T)Convert.ChangeType(cookie.Value, typeof(T));}/// <summary>/// 从一个Cookie中读取【JSON字符串】值并反序列化成一个对象,用于读取复杂对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="cookie"></param>/// <returns></returns>public static T FromJson<T>(this HttpCookie cookie){if( cookie == null )return default(T);return cookie.Value.FromJson<T>();}/// <summary>/// 将一个对象写入到Cookie/// </summary>/// <param name="obj"></param>/// <param name="name"></param>/// <param name="expries"></param>public static void WriteCookie(this object obj, string name, DateTime? expries){if( obj == null )throw new ArgumentNullException("obj");if( string.IsNullOrEmpty(name) )throw new ArgumentNullException("name");HttpCookie cookie = new HttpCookie(name, obj.ToString());if( expries.HasValue )cookie.Expires = expries.Value;HttpContext.Current.Response.Cookies.Add(cookie);}/// <summary>/// 删除指定的Cookie/// </summary>/// <param name="name"></param>public static void DeleteCookie(string name){if( string.IsNullOrEmpty(name) )throw new ArgumentNullException("name");HttpCookie cookie = new HttpCookie(name);// 删除Cookie,其实就是设置一个【过期的日期】cookie.Expires = new DateTime(1900, 1, 1);HttpContext.Current.Response.Cookies.Add(cookie);}
}

更完整的代码可以从本文的示例代码中获得。(文章底部有下载地址)

使用方式:

public static class TestClass
{public static void Write(){string str = "中国";int aa = 25;DisplaySettings setting = new DisplaySettings { Style = 3, Size = 50 };DateTime dt = new DateTime(2012, 1, 1, 12, 0, 0);str.WriteCookie("Key1", DateTime.Now.AddDays(1d));aa.WriteCookie("Key2", null);setting.ToJson().WriteCookie("Key3", null);dt.WriteCookie("Key4", null);}public static void Read(){HttpRequest request = HttpContext.Current.Request;string str = request.Cookies["Key1"].GetString();int num = request.Cookies["Key2"].ToInt(0);DisplaySettings setting = request.Cookies["Key3"].FromJson<DisplaySettings>();DateTime dt = request.Cookies["Key4"].ConverTo<DateTime>();}    
}

注意哦:以上代码中都是直接使用字符串"Key"的形式,这种方式对于大一些的程序在后期可能会影响维护。
所以建议:将访问Cookie所使用的Key能有一个类来统一的定义,或者将读写操作包装成一些属性放在一个类中统一的管理。

public static class CookieValues
{// 建议把Cookie相关的参数放在一起,提供 get / set 属性(或者方法)来访问,以避免"key"到处乱写public static string AAA{get { return HttpContext.Current.Request.Cookies["Key1"].GetString(); }}public static int BBB{get { return HttpContext.Current.Request.Cookies["Key2"].ToInt(0); }}public static DisplaySettings CCC{get { return HttpContext.Current.Request.Cookies["Key3"].FromJson<DisplaySettings>(); }}public static DateTime DDD{get { return HttpContext.Current.Request.Cookies["Key4"].ConverTo<DateTime>(); }}
}

好了,就到这里吧。本文的所有示例代码可以点击此处下载。

二天时间写此文,希望能给您一点收获。如果认为此文对您有帮助,别忘了支持一下哦。

转载于:https://www.cnblogs.com/fcsh820/archive/2011/07/06/2098774.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275402.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三年经验前端社招——丰巢科技

大家好&#xff0c;我是若川。最近组织了源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》&#xff0c;已经有超50人提交了笔记&#xff0c;群里已经有超1200人&#xff0c;感兴趣的可以点此链接扫码加我微信 ruochuan12 参与。本文经作者lxcan 授权转载&am…

数字集成电路物理设计_数字世界的物理词汇

数字集成电路物理设计Nineteen Eighty-Four is my favourite novel; I must have read it half a dozen times. There are many reasons why I believe it to be a work of literary genius, but recently I’ve been thinking about one specific aspect of it that has a ver…

yum安装Docker失败No package docker available

2019独角兽企业重金招聘Python工程师标准>>> 原因&#xff1a;yum没有找到docker包&#xff0c;更新epel第三方软件库。 yum install epel-release再yum安装docker&#xff1a; yum install -y docker转载于:https://my.oschina.net/yuantangxi/blog/3033800

黑客宣言_情感设计宣言

黑客宣言重点 (Top highlight)I have a feeling that this article is going to be slightly different from the rest of the articles I’ve recently seen or read. Everybody seems to be fighting on topics such as “UX designer or Product Designer”? “UX/UI is ok…

[转]VS2010中的单元测试

本文转自:http://zxianf.blog.163.com/blog/static/30120701201101011757499/ 在VS2010中&#xff0c;单元测试的功能很强大&#xff0c;使得建立单元测试和编写单元测试代码&#xff0c;以及管理和运行单元测试都变得简单起来&#xff0c;通过私有访问器可以对私有方法也能进行…

三年经验前端社招——Shopee

大家好&#xff0c;我是若川。最近组织了源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》&#xff0c;已经有超50人提交了笔记&#xff0c;群里已经有超1200人&#xff0c;感兴趣的可以点此链接扫码加我微信 ruochuan12本文经作者lxcan 授权转载&#xff0…

简易拨号器iCall

iCall是由哥开发的一款android平台的电话拨号小工具&#xff0c;简单不能再简单的Android手机拨号程序。 代码不过几行&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/…

苹果手机隐私分析数据是什么_苹果公司以用户为中心的隐私保护方法能教给我们什么?

苹果手机隐私分析数据是什么重点 (Top highlight)Moving beyond the rollercoaster of excitement and controversy Apple has been in for the last week, there was one thing in the WWDC keynote that stood out for me. One thing I really appreciated seeing. There is …

为什么 Vue2 this 能够直接获取到 data 和 methods ? 源码揭秘!

1. 前言大家好&#xff0c;我是若川。最近组织了源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》&#xff0c;已经有超50人提交了笔记&#xff0c;群里已经有超1200人&#xff0c;感兴趣的可以点此链接扫码加我微信 ruochuan12之前写的《学习源码整体架构系…

钮扣电池电压电量_纽扣厂

钮扣电池电压电量S. is a designer and works at the button factory. Despite its scary look, S. goes there every day, and he loves his routine, never missing a day!S.是一位设计师&#xff0c;在按钮工厂工作。 尽管看上去很恐怖&#xff0c;S。每天都去那里&#xff…

18秋学期《计算机网络》在线作业,18秋北交《计算机应用基础及计算机网络与应用》在线作业一-2辅导资料.docx...

18秋北交《计算机应用基础及计算机网络与应用》在线作业一-2辅导资料.docx18 秋北交计算机应用基础及计算机网络与应用在线作业一-21、B 2、D 3、B 4、A 5、B 一、单选题共 10 题&#xff0c;40 分1、决定局域网特性的主要技术 要素包括( )、传输介质与介 质访问控制方法。A 所…

三年经验前端社招——慧择网

大家好&#xff0c;我是若川。最近组织了源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》&#xff0c;已经有超50人提交了笔记&#xff0c;群里已经有超1200人&#xff0c;感兴趣的可以点此链接扫码加我微信 ruochuan12本文经作者lxcan 授权转载&#xff0…

港口遭遇小MM

港口&#xff0c;遭遇小MM 刚开始&#xff0c;丫头看见我拍她&#xff0c;对我毫不客气地说&#xff1a;“侵犯肖像权&#xff0c;除非立刻买两份冰淇淋来&#xff01;”后来&#xff0c;她就一直跟在我屁股后面&#xff0c;求我给她拍。轮到我说话了&#xff1a;“拍一张&…

印发 指南 通知_通知设计的综合指南

印发 指南 通知重点 (Top highlight)Peripheral messages in digital products, collectively known as notifications, should never harm the user experience. Instead, they must contribute to an experience that helps people accomplish a goal. Addressing notificati…

三年经验前端社招——众安保险

大家好&#xff0c;我是若川。最近组织了源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》&#xff0c;已经有超50人提交了笔记&#xff0c;群里已经有超1200人&#xff0c;感兴趣的可以点此链接扫码加我微信 ruochuan12本文经作者lxcan 授权转载&#xff0…

现代人的压力和焦虑_设计师如何建立减少焦虑和压力的体验

现代人的压力和焦虑From my Brooklyn apartment in New York City, I watch Gov. Andrew Cuomo share the daily Covid-19 death toll with the nation. I watch his broadcast every day, around 11 a.m. I dubbed Cuomo America’s #crisisdaddy and have posted so many Ins…

我是如何零基础入门前端开发的(2021 版)

大家好&#xff0c;我是若川。最近组织了源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》&#xff0c;已经有超50人提交了笔记&#xff0c;群里已经有超1200人&#xff0c;感兴趣的可以点此链接扫码加我微信 ruochuan12大家好&#xff0c;我是山山而川&…

去贵阳参观大数据到哪参观_您必须参观的四个世界

去贵阳参观大数据到哪参观Video games have always aimed to create a world separate from our own, with experiences gamers couldn’t get anywhere else. As technology has raced forward with time, these worlds have become more realistic, more believable, and at …

1年工作经验8月份大厂面试全记录

大家好&#xff0c;我是若川。最近组织了源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》&#xff0c;已经有超50人提交了笔记&#xff0c;群里已经有超1200人&#xff0c;感兴趣的可以点此链接扫码加我微信 ruochuan12本文来自读者AaronKwong 投稿。他参与…

axure ui设计_了解针对UI / UX设计人员的Axure RP 9

axure ui设计Axure is a powerful prototyping software with a lot of history. It has been around for many years and is available for Windows and Mac. Axure gained a lot of functionality over time, and today you can look at Axure as all in one tool. You can b…