详细总结介绍Get和Post,Session和Cookies,Token和Cookies自登陆的思路

Sessions和Cookies

一、会话机制

Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份Session通过在服务器端记录信息确定用户身份

一次会话指的是:就好比打电话,A给B打电话,接通之后,会话开始,直到挂断电话,该次会话就结束了,而浏览器访问服务器,就跟打电话一样,浏览器A给服务器发送请求,访问web程序,该次会话就已经接通,其中不管浏览器发送多少请求(就相当于接通电话后说话一样),都视为一次会话,直到浏览器关闭,本次会话结束。其中注意,一个浏览器就相当于一部电话,如果使用火狐浏览器,访问服务器,就是一次会话了,然后打开google浏览器,访问服务器,这是另一个会话,虽然是在同一台电脑,同一个用户在访问,但是,这是两次不同的会话。

知道了什么是会话后,思考一个问题,一个浏览器访问一个服务器就能建立一个会话,如果别的电脑,都同时访问该服务器,就会创建很多会话,就拿一些购物网站来说,我们访问一个购物网站的服务器,会话就被创建了,然后就点击浏览商品,对感兴趣的商品就先加入购物车,等待一起付账,这看起来是很普通的操作,但是想一下,如果有很多别的电脑上的浏览器同时也在访问该购物网站的服务器,跟我们做类似的操作呢?服务器又是怎么记住用户,怎么知道用户A购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,不能放入用户B或用户C的购物车内的呢?所以就有了cookie和session这两个技术,就像第一行说的那样,cookie和session用来跟踪用户的整个会话,

Cookie和Session之间的区别和联系

假如一个咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:

1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。但是http协议本身是无状态的

2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。也就是cookie。 顾客就相当于浏览器,cookie如何工作,下面会详细讲解

3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。

由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择

 

二、Cookie

上面已经介绍了为什么要使用Cookie,以及Cookie的一些特点,比如保存在客户端,用来记录用户身份信息的,现在来看看如何使用Cookie。

借着上面会员卡的例子来说,采用的是第二种方案,其中还需要解决的问题就是:如何分发会员卡,会员卡的内容,客户如何使用会员卡,会员卡的有效日期,会员卡的使用范围

1、如何分发会员卡、会员卡的内容:也就是cookie是如何创建的?创建后如何发送给客户端?

由服务器进行创建,也就相当于咖啡店来创建会员卡,在创建会员卡的同时,就会将会员卡中的内容也给设了

Cookie cookie = new Cookie(key,value);  //以键值对的方式存放内容,

response.addCookie(cookie);  //发送回浏览器端

注意:一旦cookie创建好了,就不能在往其中增加别的键值对,但是可以修改其中的内容,

cookie.setValue();  //将key对应的value值修改

2、客户如何使用会员卡,cookie在客户端是如何工作的,工作原理是什么?

 

一般来讲很多有以下参数

 

expire 过期时间


path 路径


domain 域名


secure  它主要是用来设置是否对 cookie 进行加密传输,默认为 false,若设置为 ture,则只有在使用 HTTPS 的情况下,这个 cookie 才可以被设置


httponly  置是否只使用 HTTP 访问cookie,若设置为 true,则客户端脚本(如JavaScript)将无法访问该 cookie,这个参数一定程度上可以降低 XSS 攻击的风险

这个过程就相当于,咖啡店创建好了会员卡,并且已经设置了其中的内容,交到了客户手中,下次客户过来时,就带着会员卡过来,就知道你是会员了,然后咖啡店就拿到你的会员卡对其进行操作。

set_cookie(key, value='', max_age=None, expires=None):设置Cookie

  • key、value都是字符串类型
  • max_age是一个整数,表示在指定秒数后过期
  • expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期,注意datetime和timedelta值只有在使用PickleSerializer时才可序列化
  • max_age与expires二选一
  • 如果不指定过期时间,则两个星期后过期

3.会员卡的使用范围?

比如星巴克在北京有一个分店,在上海也有一个分店,我们只是在北京的星巴克办理了会员卡,那么当我们到上海时,就不能使用该会员卡进行打折优惠了。而cookie也是如此,可以设置服务器端获取cookie的访问路径,而并非在服务器端的web项目中所有的servlet都能访问该cookie。

cookie默认路径:当前访问的servlet父路径。

例如:http://localhost:8080/test01/a/b/c/SendCookieServlet

默认路径:/test01/a/b/c  也就是说,在该默认路径下的所有Servlet都能够获取到cookie,/test01/a/b/c/MyServlet 这个MyServlet就能获取到cookie。

修改cookie的访问路径

setPath("/");  //在该服务器下,任何项目,任何位置都能获取到cookie,

通途:保证在tomcat下所有的web项目可以共享相同的cookie 

例如:tieba , wenku , beike 多个项目共享数据。例如用户名。

setPath("/test01/");  //在test01项目下任何位置都能获取到cookie。

4、总结Cookie:

工作流程:

  • 1. servlet创建cookie,保存少量数据,发送浏览器。
  • 2. 浏览器获得服务器发送的cookie数据,将自动的保存到浏览器端。
  • 3. 下次访问时,浏览器将自动携带cookie数据发送给服务器。

cookie操作

  • 1.创建cookie:new Cookie(name,value)
  • 2.发送cookie到浏览器:HttpServletResponse.addCookie(Cookie)
  • 3.servlet接收cookie:HttpServletRequest.getCookies()  浏览器发送的所有cookie

cookie特点

  • 1. 每一个cookie文件大小:4kb , 如果超过4kb浏览器不识别
  • 2. 一个web站点(web项目):发送20个
  • 3.一个浏览器保存总大小:300个
  • 4.cookie 不安全,可能泄露用户信息。浏览器支持禁用cookie操作。
  • 5. 默认情况生命周期:与浏览器会话一样,当浏览器关闭时cookie销毁的。---临时cookie

5.cookie案例

  • 会话状态管理(如用户登录状态、购物车)

  • 个性化设置(如用户自定义设置)

  • 浏览器行为跟踪(如跟踪分析用户行为历史记录,用户名)

5.1.记住用户名

登录时,在服务器端获取到用户名,然后创建一个cookie,将用户名存入cookie中,发送回浏览器端,然后浏览器下次在访问登录页面时,先拿到cookie,将cookie中的信息拿出来,看是否保存了该用户名,如果保存了,那么直接用他,如果没有,则自己手写用户名。

5.2.历史记录

比如购物网站,都会有我们的浏览记录的,实现原理其实也是用cookie技术,每浏览一个商品,就将其存入cookie中,到需要显示浏览记录时,只需要将cookie拿出来遍历即可。  

三.session

同样,会员卡的例子的第三种方法,发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。 这就是session的用法,在服务器端来保持状态,保存一些用户信息。

功能作用:服务器用于共享数据技术

当浏览器访问服务器的时候,第一次是没有cookies的,里面自然没有session,因此服务器懒加载request的session,获取不到就创建,获取到就读取信息,创建的session的时候会有一个sessionid专门标识这个session,然后跟着cookies,返回给浏览器,浏览器保存在本地,每次请求就带上cookies,由服务器解析出sessionid,来记录用户行为

1.session原理分析:

首先浏览器请求服务器访问web站点时,程序需要为客户端的请求创建一个session的时候,服务器首先会检查这个客户端请求是否已经包含了一个session标识、称为SESSIONID,如果已经包含了一个sessionid则说明以前已经为此客户端创建过session,服务器就按照sessionid把这个session检索出来使用,如果客户端请求不包含session id,则服务器为此客户端创建一个session并且生成一个与此session相关联的session id,sessionid 的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个sessionid将在本次响应中返回到客户端保存,保存这个sessionid的方式就可以是cookie,这样在交互的过程中,浏览器可以自动的按照规则把这个标识发回给服务器,服务器根据这个sessionid就可以找得到对应的session,又回到了这段文字的开始。

 

以DJango为例,获取到session方式为,为什么用request来获取,上面已经解释了,可以理解为OC懒加载,况且DJango中间层拦截会提取cookie信息,没有创建,有的话提取,我们只需要直接获取即可

request.session

 以登录最简单的POST为例

def login_handle(request):
    request.session['name'] = request.POST['username']
    request.session.set_expiry(0)

    return redirect(reverse('booktest:mainTest'))

2.session的一些小疑问

session就是一个字典对象,只是key可以重复

1.session是什么时候创建的,谁创建的?

它是由服务器根据请求头里面的Cookies里面的session信息,没有的话就创建出来,绑定一个id,和cookies一起返回到客户端

2.session怎么存储?存储到哪里?

以DJango服务器为例,默认配置是在sqlite3里面的,如果我们配置成Mysql,那么就会存入数据库中的session表中,如果我们配置了Redis,那么session就会存储在redis内存中,效率就更高,如下图,左边是Mysql,右边是redis,我们本来是存在mysql,可以再表中查出来,现在清掉了,配置成了右边的redis,可以看到对应的value是base64加密的

可以自己创建出来抓包试试,这里存的key就是cookies传递的sessionid,因此在cookie有效期内或者服务器的session没过期之前,都可以通过这个id来进行数据的记录,实现了用户行为的记录

3.session生命周期

常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session 

恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,一般是30分钟,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间

很明显,服务器的session由服务器自己维护,客户端在有效期内都可以记录,但是不小心清了cookies,就会导致登录失败,会重新分配新的session和id,那么老的session会在自己配置的时间内消失

session的生命周期就是:

创建:第一次调用getSession()

销毁:

1、超时,默认30分钟

2、执行api:session.invalidate()将session对象销毁、setMaxInactiveInterval(int interval) 设置有效时间,单位秒

3、服务器非正常关闭

如果正常关闭,session就会被持久化(写入到文件中,因为session默认的超时时间为30分钟,正常关闭后,就会将session持久化,等30分钟后,就会被删除)

  • set_expiry(value):设置会话的超时时间
  • 如果没有指定,则两个星期后过期
  • 如果value是一个整数,会话将在values秒没有活动后过期
  • 若果value是一个imedelta对象,会话将在当前时间加上这个指定的日期/时间过期
  • 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
  • 如果value为None,那么会话永不过期

4.session id的URL重写

当浏览器将cookie禁用,基于cookie的session将不能正常工作,每次使用request.session都将创建一个新的session。达不到session共享数据的目的,但是我们知道原理,只需要将session id 传递给服务器session就可以正常工作的。

以下是JAVA的解决方案

解决:通过URL将session id 传递给服务器:URL重写

手动方式: url;jsessionid=....

api方式:

encodeURL(java.lang.String url) 进行所有URL重写

encodeRedirectURL(java.lang.String url) 进行重定向 URL重写

这两个用法基本一致,只不过考虑特殊情况,要访问的链接可能会被Redirect到其他servlet去进行处理,这样你用上述方法带来的session的id信息不能被同时传送到其他servlet.这时候用encodeRedirectURL()方法就可以了 

如果浏览器禁用cooke,api将自动追加session id ,如果没有禁用,api将不进行任何修改。

注意:如果浏览器禁用cookie,web项目的所有url都需进行重写。否则session将不能正常工作当禁止了cookie时,

 

四、总结

从性质上讲,Session即回话,指一种持续性的,双向的连接。对于web而言,Session指用户在浏览某个网站时,从进入网站到浏览器关闭这段时间的会话。所以,Session实际上是一个特定的时间概念。

如果没有设置Session的生命周期,则SessionID存储在内存中,此时关闭浏览器Session自动注销。而我们已经知道,sessionID是通过PHPSESSID这个Cookie存储在本地的。那么在浏览器不禁用Cookie的前提下,当然可以通过setcookie()或者seession_set_cookie_params()函数设置Session的生存期,Session过期后,PHP会对其进行回收。所以,Session并非都是随着浏览器的关闭而消失的。

当然,如果你的浏览器禁用Cookie,那么所有所有Session的生存周期都是浏览器进程,关闭浏览器,再次请求页面又将重新生成Session。不过我们也有其他办法进行sessionID的传递,比如URL传参,但是这种方式极度危险,强烈不推荐。

例如你打开一个网站要登录,这个时候就会有session记录登录之前的信息,如果登录了就会保持登陆后的信息,可以理解为打电话,电话打通了,服务器一个人接了很多电话,对方通过session标识这段对话的对方是谁,如果我挂断了,下一次打电话的时候自动带上cookies里面的session,对方接起电话就知道是谁了,看下我后台的数据是否失效,没失效的话继续刚才的话题聊下去,这就保持了状态

问题一:什么是cookie和什么是session?

cookie是一种在客户端记录用户信息的技术,因为http协议是无状态的,为了解决这个问题而产生了cookie。记录用户名等一些应用

session是一种在服务端记录用户信息的技术,一般session用来在服务器端共享数据,

session一般情况下依赖于cookies,session创建出来把id通过cookies传递,然后session可以存在内存中比如redis,亦或者存入mysql,主要看你服务端的配置

问题二:cookie的工作原理?session的工作原理?

cookie工作原理,可以看上面讲解cookie的那张图,cookie是由服务器端创建发送回浏览器端的,并且每次请求服务器都会将cookie带过去,以便服务器知道该用户是哪一个。其cookie中是使用键值对来存储信息的,并且一个cookie只能存储一个键值对。所以在获取cookie时,是会获取到所有的cookie,然后从其中遍历。

session的工作原理就是依靠cookie来做支撑,第一次使用request.session时session被创建,并且会为该session创建一个独一无二的sessionid存放到cookie中,然后发送会浏览器端,浏览器端每次请求时,都会带着这个sessionid,服务器就会认识该sessionid,知道了sessionid就找得到哪个session。以此来达到共享数据的目的。 这里需要注意的是,session不会随着浏览器的关闭而死亡,而是等待超时时间。

问题三:为什么需要使用cookie和session

可以看看那个会员卡的例子,cookie和session只是为了解决http协议无状态的这种缺陷,为了记录用户信息,记录浏览器和服务器之间的状态和衍生出来的。

问题四:iOS端的cookies如何实现自登陆

  • NSHTTPCookieStorage 这个类就是一个单例,它的主要任务就是管理 Cookies, 增删改查等各种
  • NSURLRequest NSURLRequest是HTTP请求协议URL资源的消息对象Request
  • NSHTTPURLResponse

    NSHTTPURLResponse 是HTTP协议请求URL资源的响应消息对象。这个对象将HTTP协议的序列化了,可以很方便的获得的状态码(statusCode),消息报头(allHeaderFields)等信息

手动管理cookies

  • 从 NSHTTPURLResponse 获取服务器发给我们的 Cookie,此种方式获取的是Headers中的
NSHTTPURLResponse* response = (NSHTTPURLResponse* )task.response;
    NSDictionary *allHeaderFieldsDic = response.allHeaderFields;
    NSString *setCookie = allHeaderFieldsDic[@"Set-Cookie"];
    if (setCookie != nil) {
         NSString *cookie = [[setCookie componentsSeparatedByString:@";"] objectAtIndex:0];
         NSLog(@"cookie : %@", cookie); // 这里可对cookie进行存储     }
  • 从 NSHTTPCookieStorage 获取想要Cookie,此种获取方式是获取的cookies中的
//获取cookie     NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage]cookiesForURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@",kBaseURL,[NSString stringWithFormat:@"/index.php?route=mapi/%@",urlstring]]]];
    for (NSHTTPCookie *tempCookie in cookies)
    {
        //打印cookies         NSLog(@"getCookie:%@",tempCookie);
    }
    NSDictionary *Request = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
    
    NSUserDefaults *userCookies = [NSUserDefaults standardUserDefaults];
    
    [userCookies setObject:[Request objectForKey:@"Cookie"] forKey:@"cookie"];
    [userCookies synchronize];
  • 清楚cookies
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray *_tmpArray = [NSArray arrayWithArray:[cookieStorage cookies]];
    for (id obj in _tmpArray) {
        [cookieStorage deleteCookie:obj];
    }

AFNetworking 3.0管理

  • AFNetworking 3.0 默认是保存cookies的。
  • 模拟登录,保存cookie以及设置cookie:
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFHTTPSessionManager *httpManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"hostURL"] sessionConfiguration:sessionConfiguration];
AFHTTPRequestSerializer *requestSerialization = [AFHTTPRequestSerializer serializer];
requestSerialization.timeoutInterval = 15;

// 设置自动管理Cookies requestSerialization.HTTPShouldHandleCookies = YES;

// 如果已有Cookie, 则把你的cookie符上 NSString *cookie = [[NSUserDefaults standardUserDefaults] objectForKey:@"cookie"];
    if (cookie != nil) {
        [requestSerialization setValue:cookie forHTTPHeaderField:@"Cookie"];
    }

// 安全策略 AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;

[httpManager POST:@"logInURL"
       parameters:nil
         progress:NULL
          success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
              if ([responseObject[@"status"] isEqualToString:@"SUCCESS"]) {
                  //获取 Cookie                   NSHTTPURLResponse* response = (NSHTTPURLResponse* )task.response;
                  NSDictionary *allHeaderFieldsDic = response.allHeaderFields;
                  NSString *setCookie = allHeaderFieldsDic[@"Set-Cookie"];
                  if (setCookie != nil) {
                      NSString *cookie = [[setCookie componentsSeparatedByString:@";"] objectAtIndex:0];
                      // 这里对cookie进行存储                       [[NSUserDefaults standardUserDefaults] setObject:cookie forKey:@"cookie"];
                  }
              }else{
                  // 登录失败               }
          }
          failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
              NSString *errorMessage = error.userInfo[@"NSLocalizedDescription"];
          }];

web就不需要说了,很简单,都是自带的东西,只要控制消失方式就好。

问题五:iOS端不用cookies用后台自定义Token登录

一般情况都可以用Cookies来保证用户行为和一段时间的登录态。如果不用自带的,后台可以自己根据时间戳和其他方式自定义生成token来进行管理,这样子自定义更强。例如登录的时候一个接口1,成功返回token给我们,我们记录token到本地,每次请求都带上,没有的话就空串

[manager.requestSerializer setValue:[MTFUtils shared].autoToken forHTTPHeaderField:@"Authorization"];

自登陆的时候开一个接口2来校验token‘是否失效,cookies的话不能很好的控制时间,我们自定义的话可以随意控制时间,每个接口都可以进行检测控制,后台返回固定的错误码来告知客户端登录失效,重新登录。而且这个模式还能用来保证接口防刷,过多的请求,可能和自登陆没关系,但是token’的机制,可以让我们请求一些关键的接口时再请求一个获取token的值,用这个值来随意控制用户的请求行为,防止无限刷接

 

问题六:我们一般认为 Cookie 运行在客户端而 Session 运行在服务器端,所以当我们关闭浏览器(即将客户端和服务器端的链接断开)时,Session 一般就消失了而 Cookie 可以保留。这是真的吗?

虽然Session的确是运行在服务器的,但是sessionID却通过Cookie保存在客户端,所以也不尽然。可以自己设置失效是只存在内存中还是本地也存储

 

问题七:浏览器禁止 Cookie,Cookie 就不能用了,但 Session 不会受到影响,这是真的吗?

禁止了Cookie,页面的SessionID将无法使用PHPSESSID进行传递,大家可以先登陆某一网站,然后删除浏览器数据,会发现刷新页面或切换页面后将丢失登陆状态,当然我们可以用其他方式替代Cookie进行Session传值,但是很明显,Session会受Cookie禁用的影响。

问题八:Session 是否真的比 Cookie 更加安全呢?

存在本地的 Cookie 确实存在一些不安全因素,但是没人会把安全验证完全放在前端,而且我们知道一般 Session 是通过 sessionID 和 Cookie 进行绑定的,客户端的 Cookie 一旦被劫持就相当与 Session 被劫持,服务器验证 Cookie 的同时将原封不动地完成对Session的验证,所以Session比Cookie安全纯属无稽之谈。

问题九:我们发现,使用 IE 登陆腾讯网后,在同一台机子上使用 Firefox 打开腾讯的页面,发现已经有了登陆的状态,那么是否说明 Cookie 可以在不同浏览器之间共享呢?

cookie是由浏览器等客户端完全独立管理的。因为不同浏览器的Cookie管理机制不同,所以cookie不可能在浏览器之间共享。对于这个问题,其实是因为我们在安装腾讯QQ时自动安装了针对不同浏览器的插件,可以识别已经登陆的QQ号码而自动登陆。朋友们可以试试把QQ完全卸载再从网页登陆腾讯网,所以这和Cookie共享是完全没有任何关系的。

问题十:如果把别人的 Cookie 复制到我的电脑上,假设我使用一样的浏览器,那么我是否可以直接登陆别人的账号呢?

原则上讲是可行的,我们将其称为 Cookie 劫持,然而我们可以通过在 Cookie 中加入基于IP等特定信息的参数优化 Cookie 的验证过程,从而避免这一危险。

 

参考文献

https://oragekk.me/07-05-2017/iOS%E7%9A%84Cookie%E4%BD%BF%E7%94%A8.html

https://www.cnblogs.com/whgk/p/6422391.html

https://www.jianshu.com/p/bff550b3ead4

https://xujimmy.com/2017/01/11/cookie-session.html

https://blog.csdn.net/hjtl1992/article/details/26006867

GET和POST

GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二。最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数。

你轻轻松松的给出了一个“标准答案”:

  • GET在浏览器回退时是无害的,而POST会再次提交请求。

  • GET产生的URL地址可以被Bookmark,而POST不可以。

  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。

  • GET请求只能进行url编码,而POST支持多种编码方式。

  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

  • GET请求在URL中传送的参数是有长度限制的,而POST么有。

  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

  • GET参数通过URL传递,POST放在Request body中。

GET和POST是什么?HTTP协议中的两种发送请求的方法。HTTP是什么?HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议。HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。 

那么,“标准答案”里的那些区别是怎么回事?

在我大万维网世界中,TCP就像汽车,我们用TCP来运输数据,它很可靠,从来不会发生丢件少件的现象。但是如果路上跑的全是看起来一模一样的汽车,那这个世界看起来是一团混乱,送急件的汽车可能被前面满载货物的汽车拦堵在路上,整个交通系统一定会瘫痪。为了避免这种情况发生,交通规则HTTP诞生了。HTTP给汽车运输设定了好几个服务类别,有GET, POST, PUT, DELETE等等,HTTP规定,当执行GET请求的时候,要给汽车贴上GET的标签(置method为GET),而且要求把传送的数据放在车顶上(url中)以方便记录。如果是POST请求,就要在车上贴上POST的标签,并把货物放在车厢里。当然,你也可以在GET的时候往车厢内偷偷藏点货物,但是这是很不光彩;也可以在POST的时候在车顶上也放一些数据,让人觉得傻乎乎的。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。

但是,我们只看到HTTP对GET和POST参数的传送渠道(url还是requrest body)提出了要求。“标准答案”里关于参数大小的限制又是从哪来的呢?

在我大万维网世界中,还有另一个重要的角色:运输公司。不同的浏览器(发起http请求)和服务器(接受http请求)就是不同的运输公司。 虽然理论上,你可以在车顶上无限的堆货物(url中无限加参数)。但是运输公司可不傻,装货和卸货也是有很大成本的,他们会限制单次运输量来控制风险,数据量太大对浏览器和服务器都是很大负担。业界不成文的规定是,(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。超过的部分,恕不处理。如果你用GET服务,在request body偷偷藏了数据,不同服务器的处理方式也是不同的,有些服务器会帮你卸货,读出数据,有些服务器直接忽略,所以,虽然GET可以带request body,也不能保证一定能被接收到哦。

好了,现在你知道,GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同

GET和POST还有一个重大区别,简单的说:

GET产生一个TCP数据包;POST产生两个TCP数据包。

长的说:

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。

因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。因此Yahoo团队有推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么?

1. GET与POST都有自己的语义,不能随便混用。

2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。

3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

 

 

 

 

 

 

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页