真正“搞”懂HTTP协议09之这个饼干不能吃

  我们在之前的文章中介绍HTTP特性的时候聊过,HTTP是无状态的,每次聊起HTTP特性的时候,我都会回忆一下从前辉煌的日子,也就是互联网变革的初期,那时候其实HTTP不需要有状态,就是个浏览页面,没有什么需要记录信息的地方,所以无状态完全符合当时的场景。

  另外,无状态也给HTTP带来了不少的好处,正是因为无状态,这样服务器就没有状态差异,就可以很轻易的组成集群,当然,缺点就是无法支持需要记录状态的事务。为了解决这个缺点,Cookie就出现了。

一、这个饼干是什么?

  Cookie的核心作用,其实就是让HTTP拥有记忆的能力,虽然服务器记不住,但是服务器可以根据HTTP提供的信息来做出相应的逻辑和判断。你大概可以这样理解,相当于服务器给每一个客户端都贴上了一个小纸条,当服务器把纸条设置好后,会发送给客户端,客户端每次传输HTTP数据的时候,就会把这个小纸条带上发给服务器,服务器就可以见人下菜碟了。

二、小饼干是怎么工作的?

  关于Cookie的相关规范,并不在RFC2616或者RFC7230中,而是在RFC6265中,这份规范针对Cookie做了独立、详细的介绍。

  Cookie的工作过程主要应用到了两个字段:响应头字段Set-Cookie和请求头字段Cookie

  当客户端像服务器第一次请求资源的时候,服务器会使用Set-Cookie来给客户端贴上一个标签,格式就是“key=value”这样,随着响应报文一起发送给浏览器。这样浏览器在下一次发送请求的时候会自动带上cookie数据,服务器发现欸?这次请求有Cookie,就知道不是首次请求,然后识别Cookie,为该用户提供个性化的服务。

  当然,我们还可以使用多个Set-Cookie字段,来设置多个数据,让客户端携带更多的有用的信息。

  要注意的是,Cookie与操作系统无关,是浏览器绑定的,当你换了浏览器,实际上相当于一个新的初次请求。

三、Cookie的属性

  我们现在知道了,Cookie其实就是服务器委托客户端存储的一些数据,通常这些数据都是用来记录用户的关键信息。那么就需要一些额外的手段来保证Cookie的安全,这些手段就是Cookie的属性。我们下面就来看一下这些常用的有关于Cookie的属性有哪些。

  首先,我们可以通过ExpiresMax-Age设置Cookie的有效期,“Expires”俗称“过期时间”,用的是绝对时间点,可以理解为“截止日期”(deadline)。“Max-Age”用的是相对时间,单位是秒,浏览器用收到报文的时间点再加上 Max-Age,就可以得到失效的绝对时间。这两者可以同时出现,两者的失效时间可以一致,也可以不一致,但浏览器会优先采用 Max-Age 计算失效期

  其次,我们还可以设置Cookie的作用域,“Domain”和“Path”指定了 Cookie 所属的域名和路径,浏览器在发送 Cookie 前会从 URI 中提取出 host 和 path 部分,对比 Cookie 的属性。如果不满足条件,就不会在请求头里发送 Cookie。

  使用这两个属性可以为不同的域名和路径分别设置不同的Cookie,比如/a用一个Cookie,/b用另外一个Cookie,当然通常都是一个“/”就完事了。

  最后,我们要考虑的就是Cookie的安全性了,前端的同学们肯定知道,Cookie可以通过document.cookie获取,这样就导致了安全隐患,可能会导致XSS也就是跨站脚本攻击,从而窃取数据。HttpOnly属性就会告诉浏览器,此Cookie只能通过浏览器传输,禁止其它方式的访问,浏览器就会禁止任何API对cookie的访问,从而避免了XSS攻击。

  再有,SameSite属性可以防范“跨站请求伪造”(XSRF)攻击,设置成“SameSite=Strict”可以严格限定 Cookie 不能随着跳转链接跨站发送,而“SameSite=Lax”则略宽松一点,允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。

  还有一个属性叫“Secure”,表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送。但 Cookie 本身不是加密的,浏览器里还是以明文的形式存在。

四、Cookie的应用场景

  其实Cookie最常见的应用场景就是身份识别,保存用户的登录信息,实现会话事务。

  另一个常见的场景就是广告追踪,你上网的时候肯定看过很多的广告图片,这些图片背后都是广告商网站(例如 Google),它会“偷偷地”给你贴上 Cookie 小纸条,这样你上其他的网站,别的广告就能用 Cookie 读出你的身份,然后做行为分析,再推给你广告。这种 Cookie 不是由访问的主站存储的,所以又叫“第三方 Cookie”(third-party cookie)。如果广告商势力很大,广告到处都是,那么就比较“恐怖”了,无论你走到哪里它都会通过 Cookie 认出你来,实现广告“精准打击”。为了防止滥用 Cookie 搜集用户隐私,互联网组织相继提出了 DNT(Do Not Track)和 P3P(Platform for Privacy Preferences Project),但实际作用不大

五、例子

  我们先来看看简单的Cookie设置。代码也很简单:

res.setHeader("Set-Cookie", ["age=13", "name=zaking"]);

  注意,如果你要设置多个Cookie的话,第二个参数要是个数组,我们看下效果:

   这是第一次请求,然后我们刷新下页面:

   你就能看到请求头中带上了cookie,我们还可以给每个cookie设置它的作用域和失效时间:

res.setHeader("Set-Cookie", [
  "age=13; path=/; max-age=5",
  "name=zaking; path=/set-cookie; max-age=10",
  "hide=true; path=/else; max-age=1000",
]);

  记得实验效果之前把上一次的cookie清空噢。然后我们看上面的代码,path限制了路径,所以当我们访问/set-cookie的页面的时候,其实只会有两个cookie,一个有效时间5秒,一个10秒。大家可以自己试下哦:

   过了这个时间之后,你会发现一个Cookie都没有了。Cookie的属性中还有一个限制作用域的属性,叫做Domain,这个我就不试了,大家可以自行尝试一下噢。接下来我们看下,我们在页面中通过document.cookie来获取Cookie:

<body>
  Cookie
</body>
<script>
  console.log(document.cookie);
</script>

  就这么简单,重启服务刷新页面后,可以看到控制台打印出了作用域范围内的Cookie。

  我们加个HttpOnly再看看:

res.setHeader("Set-Cookie", [
  "age=13; path=/; max-age=5",
  "name=zaking; path=/set-cookie; max-age=10;HttpOnly",
  "hide=true; path=/else; max-age=1000",
]);

  结果就只剩下age了,完全符合我们的预期。

  那么例子就到这里啦,还有一些我没写出来噢,比如SameSite和Secure。其实也并不复杂,我就是懒得写了。

六、总结

  Cookie其实是有大名的,叫做Magic Cookie,意思是不透明的数据,跟饼干没啥关系噢。早期的Cookie都是存在磁盘上的文本文件,现在基本上是使用数据库存储,比如sqlite,存储的大小有一定的限制,是4k。

  如果不指定Cookie生效实践,则会在浏览器关闭后无效,也叫做会话Cookie。历史上还有Set-Cookie2和Cookie2这样的字段,但是现在没用了。

<body> Cookie </body> <script> console.log(document.cookie); </script>

本文来自博客园,作者:Zaking,转载请注明原文链接:http://www.cnblogs.com/zaking/p/17055993.html

本文转载于网络 如有侵权请联系删除

相关文章

  • java五子棋小游戏含免费源码

    游戏截图: 看一下运行效果 这里我使用的开发工具是Eclipse主要代码Main.java:publicclassMainextendsJFrame{ /* *用户登录 */ privatestaticfinallongservialVersionUID=1L; finalJLabellogoLabel=newJLabel("开心五子棋"); finalJLabellogo=newJLabel(); finalJButtonloginButton=newJButton("登陆"); finalJLabelregisterLabel=newJLabel("立即注册"); finalJLabeluserLabel=newJLabel("账号:"); finalJLabelpasswordLabel=newJLabel("密码:"); finalstaticJTextFielduserjt=newJTextField(11); finalJPasswordField

  • php apache开启跨域模式过程详解

    apaceh配置:<VirtualHost*:80 ServerAdminxxx@qq.com DocumentRoot"C:/htdocs/demo" ServerNamedev.dd.cn ##ErrorLog"logs/dummy-host.localhost-error.log" ##CustomLog"logs/dummy-host.localhost-access.log"combined <Directory"C:/htdocs/demo" #Requirealldenied HeadersetAccess-Control-Allow-Origin* </Directory </VirtualHost复制PHP文件设置:<?php header("Access-Control-Allow-Origin:*"); //处理请求输出数据 ?复制配置的含义是允许任何域发起的请求都可以获取当前服务器的数据。当然,这样有很大的危险性,恶意站点可能通过XS

  • 文件上传漏洞的矛与盾

    文件上传成因及危害在网站运营过程中,不可避免地要对网站的某些页面或者内容进行更新,这个时候需要使用到网站的文件上传功能。如果不对被上传的文件进行限制或者限制被绕过,该功能便有可能会被利用上传可执行文件、脚本文件到服务器上,从而控制整个网站,甚至如下危害:网站被控制,对文件增删改查,执行命令,链接数据库如果服务器长久未更新,可以利用exp提权,导致服务器沦陷同服务器的其他网站沦陷漏洞产生原因服务器配置不当(iis6.0等解析漏洞)当服务器配置不当时,在不需要上传页面的情况下便可导致任意文件上传。(PUT协议)iis6.0本地文件上传限制被绕过(javascript验证)只在客户端浏览器上做了文件限制而没有在远程的服务器上做限制,只需要修改数据包就可以轻松绕过限制服务端过滤不严格被绕过有一些网站使用了黑名单过滤掉了一些关键的可执行脚本文件后缀。但黑名单不全或者被绕过,比如服务端过滤掉了后缀为.php的文件,但是没有过滤掉.php3等其他可执行的脚本文件后缀,攻击者就可以上传其他的可执行的脚本文件后缀到服务器上。文件路径截断(0x00)文件解析漏洞导致文件执行(iis,apache,ngin

  • 哈夫曼树

    代码#include<iostream> #include<cstring> #include<queue> usingnamespacestd; typedefstructnode{ structnode*lchild; structnode*rchild; intweight; node(intw,structnode*l,structnode*r){ this->weight=w; this->lchild=l; this->rchild=r; } }TreeNode; structcmp{ booloperator()(TreeNode*node1,TreeNode*node2){ returnnode1->weight>node2->weight; } }; TreeNode*Create_HuffmanTree(int*weights,intsize) { priority_queue<TreeNode*,vector<TreeNode*>,cm

  • 「数字体验」Liferay数字体验平台(DXP)的好处

    随着DXP版本的发布,Liferay在它的基础产品上做了一个范式转换。通过这个版本,Liferay现在已经定义了一个路线图,以应对未来的技术趋势,比如微服务、数字体验管理、更智能、更快速的构建管理。在这篇文章中,我们将挑选一些LiferayDXP的新功能,并对它们进行详细的探讨。模块化:这实际上意味着Liferay的每个模块(特性)现在都是联合的,可以从核心Liferay安装中分离出来。虽然Liferay以前是一个单一的大型单片应用程序,但现在它由多个jar组成。这意味着企业现在可以在安装中挑选他们想要的东西,而不必为不必要的性能开销买单。优点:更简洁的安装,更少的性能开销,更易于管理的安装,更快的部署,更容易维护谁受益最大:广泛使用Liferay的几个模块的部署语义版本控制:现在,在一个Liferay实例上同时运行同一个模块的多个版本。例如,您的安装上运行了Wiki(特性)的一个版本,您现在可以根据该特性中的新需求进行更改,使用不同的版本控制,并且应用程序可以使用经过修改的版本控制服务。甚至旧版本和新版本都可以在同一个实例中使用好处:你现在可以有更新的beta版本的功能供用户使用,而

  • Spring Cloud 教程 - Eureka Server

    如何使用EurekaServer将groupId为org.springframework.cloud,artifactId为spring-cloud-starter-netflix-eureka-server的依赖添加到项目中即可引入EurekaServer,具体版本号可以参考SpringCloudProject 使用如下代码快速启动EurekaServer@SpringBootApplication@EnableEurekaServerpublicclassApplication{publicstaticvoidmain(String[]args){newSpringApplicationBuilder(Application.class).web(true).run(args); } }复制Server包含一个主页和其他的HTTPAPI,默认在/eureka/*路径下。 高可用,Zones和RegionsEureka并不包含存储,但是所有的服务实例必须发送心跳信息来更新啊们的状态,这些信息都是在内存中操作的。客户端同样也包含一个Eureka的注册信息。 默认情况下,一个Eurek

  • Science | 分析20亿行北京出租车数据 寻找你被拒载的原因

    大数据文摘作品,转载具体要求见文末作者|行者任杰吴蕾论文作者|张四海王芷阳我们都有过这样的经历:在得知你的目的地后,你的uber/滴滴接单被司机师傅取消了。师傅的理由很可能是“我现在下班了”或“我的车没油了”,但愤怒的同时你一定也会怀疑:我的目的地是不是不对师傅口味?刚拒绝我的司机是在寻找赚取更高车费的机会吗?近日关于北京出租车司机的研究结果支持了这一观点:依据乘客的目的地进行拒载,确实能赚到更多钱。由于像Uber和Lyft这样的公司正在各地形成公共交通体系,这种利益驱动的偏见可能会让部分人很难打到出租车。上个月,美国science杂志报道了两位来自中国的学者基于北京出租车数据的这一相关研究:他们通过北京出租车行业2012年间的两个月的GPS跟踪数据,分析了对出租车司机是否接受乘客要求的行为选择造成影响的客观因素:起始地点、距离远近、司机收入偏差等。然后基于大数据算法,得出了出租车司机拒载乘客这一现象背后的行为决策模式,并估计出,在北京,你会面对的出租车拒载概率是8.15%。研究这个数据集的研究者是来自于中国科学技术大学的两位计算机科学家,张四海和王芷阳,他们也都有许多不悦的打车经历

  • Django 1.10中文文档-第一个应用Part7-自定义管理站点

    目录[-]开发第一个Django应用,Part7本教程上接Part6。将继续完成这个投票应用,本节将着重讲解如果用Django自动生成后台管理网站。自定义管理表单通过admin.site.register(Question)注册了Question后,Django可以自动构建一个默认的表单。如果您需要自定义管理表单的外观和功能。你可以在注册时通过配置来实现。现在先来试试重新排序表单上的字段。只需要将admin.site.register(Question)所在行替换为:#polls/admin.py fromdjango.contribimportadmin from.modelsimportQuestion classQuestionAdmin(admin.ModelAdmin): fields=['pub_date','question_text'] admin.site.register(Question,QuestionAdmin)复制你可以参照上面的形式,创建一个模型类,将之作为第二个参数传入admin.site.registe

  • 网站前端进行违禁词/极限词过滤js代码

    varstrChar=['最佳','最具','最爱','最赚','最优','最优秀','最好','最大','最大程度','最高','最高级','最高端','最奢侈','最低','最低级','最底','最便宜','史上最低价','最流行','最受欢迎','最时尚','最聚拢','最符合','最舒适','最先','最先进','最先进科学','最先进加工工艺','最先享受','最后','最后一

  • 腾讯云云数据库Redis查询项目安全组详情api接口

    1.接口描述接口请求域名:redis.tencentcloudapi.com。 本接口(DescribeProjectSecurityGroups)用于查询项目的安全组详情。 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:DescribeProjectSecurityGroups。 Version 是 String 公共参数,本接口取值:2018-04-12。 Region 是 String 公共参数,详见产品支持的地域列表。 Product 是 String 数据库引擎名称,本接口取值:redis。 ProjectId 是 Integer 项目ID。 Offset 否 Integer 偏移量,取值为Limit的整数倍。

  • 腾讯云标签数据结构

    FailedResource失败资源信息。绑定或解绑资源标签时失败返回 被如下接口引用:TagResources,UnTagResources。 名称 类型 描述 Resource String 失败的资源六段式 Code String 错误码 Message String 错误信息 Project项目信息 被如下接口引用:DescribeProjects。 名称 类型 描述 ProjectId Integer 项目ID ProjectName String 项目名称 CreatorUin Integer 创建人uin ProjectInfo String 项目描述 CreateTime String 创建时间 ResourceIdTag资源标签键值 被如下接口引用:DescribeResourceTagsByTagKeys。 名称 类型 描述 ResourceId String 资源唯一标识注意:此字段可能返回null,表示取不到有效值。 TagKeyValues ArrayofTag 标签键值对注意:此字段可能

  • 准备开源一套异形UI控件

    今天整理磁盘,发现在一个以前加密过的一个磁盘文件中发现了一些以前做的UI代码。平时都没怎么去用,放着放着只会慢慢的去遗忘,所以打算慢慢的将一些UI代码整理整理,然后开源出来,集合广大Delphier的智慧来一起发挥发挥这些我也没啥太多用处的代码的余热。 经过最近几年来的工作轨迹来看,工作已经比较定性,相对来说已经不是太搞界面UI方面的工作了。而个人在以前很长的一段时间内,基本上很多时间从事的都是 UI方面的工作,貌似从08年开始就在开始搞UI,一直到2012年,摸爬滚打了几年,2013年开始,转到项目上了,企业级项目,相对来说,就没有那种 比较特别的UI,同时XE2出现,FMX框架的推出,已经提出了DirectUI的理念,所以那个时候,我就也慢慢放下了UI方面的学习以及研究了,以及 当时写了一部分的DirectUI,也都同时放下,不再去写了。到目前为止,Delphi已经发展到XE8,FMX也已经更加成熟了,感觉以后我们都应该 会直接使用FMX来做各种界面效果,这将会是一个趋势。 本次开源就算是个人对于以前的VCL一直发展至今的一种敬意,也算是对FMX日后发展的更加壮大的一种渴望把。 先

  • 172. 阶乘后的零

    172.阶乘后的零 给定一个整数n,返回n!结果中尾随零的数量。 提示 n!=n*(n-1)*(n-2)*...*3*2*1   示例1: 输入:n=3 输出:0 解释:3!=6,不含尾随0 复制 示例2: 输入:n=5 输出:1 解释:5!=120,有一个尾随0 复制 示例3: 输入:n=0 输出:0 复制   提示: 0<=n<=104   进阶:你可以设计并实现对数时间复杂度的算法来解决此问题吗?   解析: 看有几个5即可 但主要25有2个5,125有3个5, 而ret+=n/base会使得以后的base都少一个5,所以每次除base时,由于前面已经加上了,所以只加一次就够了 classSolution{ public: inttrailingZeroes(intn){ intret=0; intbase=5; while(base<=n) { ret+=n/base; base*=5; } returnret; } };复制   自己选择的路,跪着也要走完。朋友们,虽

  • decode函数

    含义解释:decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下:IF条件=值1THEN    RETURN(翻译值1)ELSIF条件=值2THEN    RETURN(翻译值2)    ......ELSIF条件=值nTHEN    RETURN(翻译值n)ELSE    RETURN(缺省值)ENDIF   decode(字段或字段的运算,值1,值2,值3)       这个函数运行的结果是,当字段或字段的运算的值等于值1时,该函数返回值2,否则返回值3当然值1,值2,值3也可以是表达式 生命不息,代码不止

  • 生成树的基本调整

    1.调整vlan的优先级:switch<config>#spanningvlanXpriorityY      将vlanX的优先级调整为Y,Y是4096的倍数 2.实施端口快速即portfast:     通常情况下,如果生成树中端口状态发生改变,引起生成树从新计算,那么需要大约30s收敛,这是不能承受的。     所以,我们要在连接主机的端口上实施portfast以保证生成树的稳定,它跳过了端口从LIS到LRN,LRN到FWD的过程,收敛速度很快    具体操作有两种,第一种:在所有需要的接口上单独配置,switch<config-if>#spanning-treeportfast                  &nbs

  • git 命令大全

    Git常用命令使用大全   转载:http://www.cnblogs.com/mengdd/p/4153773.html   查看、添加、提交、删除、找回,重置修改文件 githelp<command>#显示command的help gitshow#显示某次提交的内容gitshow$id gitco--<file>#抛弃工作区修改 gitco.#抛弃工作区修改 gitadd<file>#将工作文件修改提交到本地暂存区 gitadd.#将所有修改过的工作文件提交暂存区 gitrm<file>#从版本库中删除文件 gitrm<file>--cached#从版本库中删除文件,但不删除文件 gitreset<file>#从暂存区恢复到工作文件 gitreset--.#从暂存区恢复到工作文件 gitreset--hard#恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改 gitci<file>gitci.gitci-a#将gitadd,gitrm和gitci等操作都合并在一起做 

  • js防抖和节流

    常见应用场景: (1)window的resize和scroll事件;        如:滚动到页面底部加载更多,稍微滚动一下就会触发n多次scroll事件,如果每次触发scroll事件的时候都去判断一次是否已经滚动到了页面底部,无疑会造成资源的浪费。此时若使用js节流,每隔一定的时间(如500ms)进行一次判断,间隔期间只能有一次触发判断,既节省了资源,也不会影响用户体验。 (2)文字输入时的keyup事件;        如:输入搜索关键词的时候,进行自动完成或者自动联想。同理,这种情况下用户每敲击一次键盘就会触发一次keyup事件,此时用户可能连一个字都没有输入完成==,此时可以使用js防抖,在用户停止输入的一段时间后(如500ms)触发判断,进行自动联想或者自动搜索;也可以使用js节流,每隔一段时间,进行一次判断的执行,既可以实现实时的自动联想,也不会出现过于频繁的请求。 (3)元素拖拽、移动时的mousemove事件; <!DOCT

  • 缘起,在人群中,我看见你---------------装饰器

    装饰器 装饰器的定义(whatwhyhow) 1.什么是装饰器 装饰器就是装饰某一个东西的工具 2.为什么要用装饰器 因为在源函数代码不改变调用方法&原代码给原函数添加新功能,装饰器是最好的解决工具 3.怎么用装饰器 详见下面 复制 装饰器的实现思路 """ 现有一个原函数index,想要为其添加一个时间差的功能,我们应该怎么做呢 """ #方案一这就已经修改了他的原代码了 importtime defindex(x): start_time=time.time() print(f'welcometoindex{x}') time.sleep(3) print(time.time()-start_time) index(1) #方案二没有修改原函数的代码&调用,但是代码冗余 defindex(x): print(f'welcometoindex{x}') time.sleep(3) start_time=time.time() index(1) print(time.time()-start_time) start_time=time.time(

  • 常用的Hql语句

    //HQL:HibernateQueryLanguage.//特点://>>1,与SQL相似,SQL中的语法基本上都可以直接使用。//>>2,SQL查询的是表和表中的列;HQL查询的是对象与对象中的属性。//>>3,HQL的关键字不区分大小写,类名与属性名是区分大小写的。//>>4,SELECT可以省略. //1,简单的查询,Employee为实体名而不是数据库中的表名(面向对象特性)hql="FROMEmployee";hql="FROMEmployeeASe";//使用别名hql="FROMEmployeee";//使用别名,as关键字可省略 //2,带上过滤条件的(可以使用别名):Wherehql="FROMEmployeeWHEREid<10";hql="FROMEmployeeeWHEREe.id<10";hql="FROMEmployeeeWHEREe.id<10ANDe.id>5"; //3,带上排序条件的:OrderByhql="FROMEmployeeeWHEREe.id<10ORDE

  • springcloud- FeginClient 调用统一拦截添加请求头 RequestInterceptor ,被调用服务获取请求头(转载)

    来源:https://www.cnblogs.com/wenq001/p/9132118.html   使用场景:   在springcloud中通过Fegin调用远端RestApi的时候,经常需要传递一些参数信息到被调用服务中去,比如从A服务调用B服务的时候,  需要将当前用户信息传递到B调用的服务中去,我们就可以使用实现 RequestInterceptor接口,完成FeginClient请求调用时拦截请求的统一处理请求头,添加请求头信息等; @Slf4j @Component publicclassDtsInterceptorimplementsRequestInterceptor{ @Override publicvoidapply(RequestTemplaterequestTemplate){ //TODO做一些业务处理,获取数据,添加数据到请求头 requestTemplate.header(key,value); } }复制  在被调用服务中获取请求头  第一种方式: HttpServletRequestreques

  • letcode每日一题-移掉K位数字

    项目描述如下: 思路: 我自己想的是使用贪心算法 对于两个相同长度的数字序列,最左边不同的数字决定了这两个数字的大小,例如,对于A=1axxxA=1axxx,B=1bxxxB=1bxxx, 如果a>ba>b则A>BA>B。 基于此,我们可以知道,若要使得剩下的数字最小,需要保证靠前的数字尽可能小。 基于此我的代码实现如下: publicStringremoveKdigits(Stringnum,intk){ LinkedList<Character>tmp=newLinkedList<>(); inti=0; //构建临时结果列表 for(;i<num.length()-k;i++){ tmp.add(num.charAt(i)); } for(;i<num.length();i++){ tmp.add(num.charAt(i)); //删除一个数字 removeBig(tmp); } StringBuilderresult=newStringBuilder(); for(CharactercharTmp:tmp){

相关推荐

推荐阅读