韩源-末日生存手册 - request
type: channel
link: https://kerryhan.cn/index.php/tag/request
items: 详解HTTP
items: 单点登录原理及实现
items: MockMvc详解
items: springboot+mybatisPlus代码层级梳理
items: SpringMVC的常用注解

详解HTTP
type: item
date: 2021-07-12T12:29:00+00:00
description: 详解HTTPWeb及网络基础为了更好的理解什么是HTTP协议，我们需要先了解TCP/IP协议族。目前通常使用的网络都是在基于TCP/IP协议族的情况下进行信息传输，而HTTP也实际上是属于TCP/IP协议模型。要知道，不同的计算机之间要通过网络进行通信，那么必须遵循统一的规定，才能进行交流。这也就是协议的作用，通过制定规约，让不同的计算机可以进行信息互换。TCP/IP协议最重要的一点是对于信息加工传输进行了分层处理，这种分层结构清晰明了。TCP/IP协议族按层次划分为应用层、网络层、传输层、数据链路层。发送端数据依次经过应用层、网络层、传输层、数据链路层；接收端依次从数据链路层、传输层、网络层、应用层接收数据。而我们的HTTP协议就应用在应用层。HTTP报文用于HTTP协议交互的信息被称为是HTTP报文。客户端的HTTP报文叫做请求报文，响应端的HTTP报文称为响应报文。HTTP的报文是由多行数据构成的字符串文本。其结构大致可以分为报文首部和报文主体两块，两者通过空行进行划分，通常，报文是没有主体的。HTTP结构HTTP请求报文分为报文首部、空行、报文主体，其中报文首部内存放了请求行、请求首部字段、通用首部字段、实体首部字段和其他。HTTP响应报文分为报文首部、空行、报文主体，其中报文首部分为状态行、响应首部字段、通用首部字段、实体首部字段以及其他。HTTP状态码1XX：通知1XX系列响应代码仅在与HTTP服务器沟通时使用。100("Continue") 重要程度：中等，但（写操作时）很少用。这是对HTTP LBYL（look-before-you-leap）请求的一个可能的响应。该响应代码表明：客户端应重新发送初始请求，并在请求中附上第一次请求时未提供的（可能很大或者包含敏感信息的）表示。客户端这次发送的请求不会被拒绝。对LBYL请求的另一个可能的响应是417("Expectation Failed")。请求报头：要做一个LBYL请求，客户端必须把Expect请求报头设为字符串"100-continue"。除此以外，客户端还需要设置其他一些报头，服务器将根据这些报头决定是响应100还是417。101("Switching Protocols") 重要程度：非常低。当客户端通过在请求里使用Upgrade报头，以通知服务器它想改用除HTTP协议之外的其他协议时，客户端将获得此响应代码。101响应代码表示“行，我现在改用另一个协议了”。通常HTTP客户端会在收到服务器发来的101响应后关闭与服务器的TCP连接。101响应代码意味着，该客户端不再是一个HTTP客户端，而将成为另一种客户端。尽管可以通过Upgrade报头从HTTP切换到HTTPS，或者从HTTP1.1切换到某个未来的版本，但实际使用Upgrade报头的情况比较少。Upgrade报头也可用于HTTP切换到一个完全不同的协议（如IRC）上，但那需要在Web服务器切换为一个IRC服务器的同时，Web客户端切换为一个IRC的客户端，因为服务器将立刻在同一个TCP连接上开始使用新的协议。请求报头：客户端把Upgrade报头设置为一组希望使用的协议。响应报头：如果服务器同意切换协议，它就返回一个Upgrade报头，说明它将切换到那个协议，并附上一个空白行。服务器不用关闭TCP链接，而是直接在该TCP连接上开始使用新的协议。2XX: 成功2XX系列响应代码表明操作成功了。200("OK") 重要程度：非常高。一般来说，这是客户端希望看到的响应代码。它表示服务器成功执行了客户端所请求的动作，并且在2XX系列里没有其他更适合的响应代码了。实体主体：对于GET请求，服务器应返回客户端所请求资源的一个表示。对于其他请求，服务器应返回当前所选资源的一个表示，或者刚刚执行的动作的一个描述。-201("Created")重要程度：高。当服务器依照客户端的请求创建了一个新资源时，发送此响应代码。响应报头：Location报头应包含指向新创建资源的规范URI。实体主体：应该给出新创建资源的描述与链接。若已经在Location报头里给出了新资源的URI，那么可以用新资源的一个表示作为实体主体。-202("Accepted")重要程度：中等。客户端的请求无法或将不被实时处理。请求稍后会被处理。请求看上去是合法的，但在实际处理它时有出现问题的可能。若一个请求触发了一个异步操作，或者一个需要现实世界参与的动作，或者一个需要很长时间才能完成且没必要让Web客户端一直等待的动作时，这个相应代码是一个合适的选择。响应报头：应该把未处理完的请求暴露为一个资源，以便客户端稍后查询其状态。Location报头可以包含指向该资源的URI。实体主体：若无法让客户端稍后查询请求的状态，那么至少应该提供一个关于何时能处理该请求…

单点登录原理及实现
type: item
date: 2021-03-17T07:13:00+00:00
description: 一、单系统登录机制1、http无状态协议 web应用采用browser/server架构，http作为通信协议。http是无状态协议，浏览器的每一次请求，服务器会独立处理，不与之前或之后的请求产生关联，这个过程用下图说明，三次请求/响应对之间没有任何联系3c91a3bf-25d8-4b1f-8e4a-68535c51aaa8 但这也同时意味着，任何用户都能通过浏览器访问服务器资源，如果想保护服务器的某些资源，必须限制浏览器请求；要限制浏览器请求，必须鉴别浏览器请求，响应合法请求，忽略非法请求；要鉴别浏览器请求，必须清楚浏览器请求状态。既然http协议无状态，那就让服务器和浏览器共同维护一个状态吧！这就是会话机制2、会话机制 浏览器第一次请求服务器，服务器创建一个会话，并将会话的id作为响应的一部分发送给浏览器，浏览器存储会话id，并在后续第二次和第三次请求中带上会话id，服务器取得请求中的会话id就知道是不是同一个用户了，这个过程用下图说明，后续请求与第一次请求产生了关联8a9fb230-d506-4b19-b821-4001c68c4588 服务器在内存中保存会话对象，浏览器怎么保存会话id呢？你可能会想到两种方式请求参数cookie 将会话id作为每一个请求的参数，服务器接收请求自然能解析参数获得会话id，并借此判断是否来自同一会话，很明显，这种方式不靠谱。那就浏览器自己来维护这个会话id吧，每次发送http请求时浏览器自动发送会话id，cookie机制正好用来做这件事。cookie是浏览器用来存储少量数据的一种机制，数据以”key/value“形式存储，浏览器发送http请求时自动附带cookie信息 tomcat会话机制当然也实现了cookie，访问tomcat服务器时，浏览器中可以看到一个名为“JSESSIONID”的cookie，这就是tomcat会话机制维护的会话id，使用了cookie的请求响应过程如下图518293d9-64b2-459c-9d45-9f353c757d1f3、登录状态 有了会话机制，登录状态就好明白了，我们假设浏览器第一次请求服务器需要输入用户名与密码验证身份，服务器拿到用户名密码去数据库比对，正确的话说明当前持有这个会话的用户是合法用户，应该将这个会话标记为“已授权”或者“已登录”等等之类的状态，既然是会话的状态，自然要保存在会话对象中，tomcat在会话对象中设置登录状态如下用户再次访问时，tomcat在会话对象中查看登录状态HttpSession session = request.getSession();session.setAttribute("isLogin", true);HttpSession session = request.getSession();session.getAttribute("isLogin"); 实现了登录状态的浏览器请求服务器模型如下图描述 每次请求受保护资源时都会检查会话对象中的登录状态，只有 isLogin=true 的会话才能访问，登录机制因此而实现。二、多系统的复杂性 web系统早已从久远的单系统发展成为如今由多系统组成的应用群，面对如此众多的系统，用户难道要一个一个登录、然后一个一个注销吗？就像下图描述的这样6dfbb0b1-46c0-4945-a3bf-5f060fa80710 web系统由单系统发展成多系统组成的应用群，复杂性应该由系统内部承担，而不是用户。无论web系统内部多么复杂，对用户而言，都是一个统一的整体，也就是说，用户访问web系统的整个应用群与访问单个系统一样，登录/注销只要一次就够了9fe14ab3-4254-447b-b850-0436e628c254 虽然单系统的登录解决方案很完美，但对于多系统应用群已经不再适用了，为什么呢？ 单系统登录解决方案的核心是cookie，cookie携带会话id在浏览器与服务器之间维护会话状态。但cookie是有限制的，这个限制就是cookie的域（通常对应网站的域名），浏览器发送http请求时会自动携带与该域匹配的cookie，而不是所有cookie4d58ccfa-0114-486d-bec2-c28f2f9eb513 既然这样，为什么不将web应用群中所有子系统的域名统一在一个顶级域名下，例如“*.baidu.com”，然后将它们的cookie域设置为“baidu.com”，这种做法理论上是可以的，甚至早期很多多系统登录就采用这种同域名共享cookie的方式。 然而，可行并不代表好，共享cookie的方式存在众多局限。首先，应用群域名得统一；其次，应用群各系统使用的技术（至少是web服务器）要相同，不然cookie的key值（tomcat为JSESSIONID）不同，无法维持会话…

MockMvc详解
type: item
date: 2020-05-11T15:18:00+00:00
description: MockMvc详解MockMvc是什么简单来说，对于web应用来讲，你需要对你的各个模块进行测试，但是通过启动项目使用postman来测试的话比较麻烦（程序启动速度慢，测试验证不方便，依赖网络环境），那么为了使我们的单元测试更加简单、高效，我们引入了MockMvcMockMvc实现了对于Http请求的模拟，能够直接使用网络的形式，转换到contoller的调用，可以使得测试速度快、不依赖网络环境，而且还提供了专门的一套验证的工具。测试的逻辑MockMvcBuilder构造MockMvc的构造器MockMvc调用perform，执行一个RequestBuilder请求，调用controller的业务处理逻辑perform返回ResultActions,返回操作的结果，通过ResultActions，提供了统一的验证方式使用StatusResultMatchers对请求结果进行验证使用ContentResultMatchers对请求的内容进行验证如何获取mockMvc实例两个获取mockMvc实例的方式：StandaloneMockMvcBuilderDefaultMockMvcBuilder具体实现方式：MockMvcBuilders.webAppContextSetup(WebApplicationContext context)指定WebApplicationContext，将会从该上下文获取相应的控制器并得到相应的MockMvcMockMvcBuilders.standaloneSetup(Object... controllers)通过参数指定一组控制器，这样就不需要从上下文获取了比如this.mockMvc = MockMvcBuilders.standaloneSetup(this.controller).build();## 构造请求——MockMvcRequestBuilders构造请求示例：MockMvcRequestBuilders.get("/user")MockMvcRequestBuilders主要APIMockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables)：根据uri模板和uri变量值得到一个GET请求方式的MockHttpServletRequestBuilder；如get(/user/{id}, 1L)； MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables)：同get类似，但是是POST方法； MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables)：同get类似，但是是PUT方法； MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) ：同get类似，但是是DELETE方法； MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables)：同get类似，但是是OPTIONS方法； MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables)： 提供自己的Http请求方法及uri模板和uri变量，如上API都是委托给这个API； MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables)：提供文件上传方式的请求，得到MockMultipartHttpServletRequestBuilder； RequestBuilder asyncDispatch(final MvcResult mvcResult)：创建一个从启动异步处理的请求的MvcResult进行异步分派的RequestBuilder； 指定请求参数——MockHttpServletRequestBuilder当然，我们不仅可以设置它的请求方式，同样也可以设置它的请求参数MockHttpServletRequestBuilder主要APIMockHttpServletRequestBuilder header(String name, Object... values…

springboot+mybatisPlus代码层级梳理
type: item
date: 2020-04-30T14:40:00+00:00
description: 代码层级梳理代码层级annotation层ExcelVoAttribut主要用于写@ExcelVoAttribute注解，可以更灵活的配置Excel数据表导出的一些基本配置LogDirection主要用于写@LogDirection注解，注解里包含一个字段（接口描述），通过接口添加这个注解，填写上接口的功能，当用户在访问接口时候，可以利用aop技术，把用户的操作记到日志里aspect层LogDrectionAspect主要定义了aop切点的位置和增强的方法/** * @Author Johnny * @Date 2020/4/16 * @Version 1.0 */ @Aspect @Component @Slf4j public class LogDirectionAspect { @Pointcut("@annotation(logDirection)") public void doLogDirection(LogDirection logDirection){ } @Around(value = "doLogDirection(logDirection)",argNames = "pjp,logDirection") public Object doBefore(ProceedingJoinPoint pjp,LogDirection logDirection) throws Throwable{ if (!"".equals(logDirection.direction())) { log.info(logDirection.direction()+"接口被调用"); return pjp.proceed(); } return "接口信息不规范"; } }@Pointcut定义切点，此处定义切点为使用@LogDirection的方法@Around定义增强的方法，通过around的参数ProceedingJoinPoint可以很好的控制程序能不能继续执行下一步，在权限判定发挥着比较重要的作用拓展：利用下面的这种方法，需要在xml文件中配置bean实例，当然也可以在方法中通过手动扫包的方法获得bean实例进行操作/** * @Author Johnny * @Date 2020/4/16 * @Version 1.0 */ @Aspect public class MyAdvice { /** * 配置切点 */ @Pointcut("execution(* com.soft1851.spring.web.dao..*.insert*(..))") public void pointCut() { } /** * 配置前置增强 */ @Before("MyAdvice.pointCut()") public void beforeMethod() { System.out.println("等待数据插入"); } /** * 配置后置增强 */ @AfterReturning("execution(* com.soft1851.spring.web.dao..*.*(..))") public void afterMethod(){ System.out.println("关闭数据库"); } }xml配置实例 <bean name="forumDao" class="com.soft1851.spring.web.dao.impl.ForumDaoImpl"/> <bean name="myAdvice" class="com.soft1851.spring.web.interceptor.MyAdvice"/> <aop:aspectj-autoproxy/>common层ResponseResult和ResultCode这两个类可以将响应体统一进行封装，将接口的响应体规范化，使前端获取数据也更加友好贴下代码，防止以后找不到ResponseResult类package com.soft1851.music.admin.common; import lombok.Data; import java.io.Serializable; /** * @author Johnny * @Date: 2020/4/21 19:52 * @Description: */ @Data public class ResponseResult implements Serializable { private static final long serialVersionUID = -3948389268046368059L; private Integer code; private String msg; private Obje…

SpringMVC的常用注解
type: item
date: 2020-03-31T16:52:00+00:00
description: @Controller处理由DispatcherServlet 分发的请求，用于类上把用户请求的数据经过业务处理层处理之后封装成一个Model再把该Model 返回给对应的View 进行展示@RequestMapping处理请求地址映射的注解，可用于类或方法属性value： 指定请求的实际地址，指定的地址可以是URI Template 模式method： 指定请求的method类型， GET、POST、PUT、DELETE...consumes： 指定处理请求的提交内容类型（Content-Type），例如application/json, text/htmlproduces: 指定返回的内容类型，仅当request请求头中的(Accept)类型中包含该指定类型才返回params： 指定request中必须包含某些参数值是，才让该方法处理headers： 指定request中必须包含某些指定的header值，才能让该方法处理请求@Resource、@Autowired在bean的注入时使用写在字段和setter方法上。两者如果都写在字段上，那么就不需要再写setter方法@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上，即取出uri模板中的变量作为参数@requestParam主要用于在SpringMVC后台控制层获取参数，类似一种是request.getParameter("name")@ResponseBody将Controller的方法返回的对象，通过适当的HttpMessageConverter转换为指定格式@Component通用注解（可代替@Repository @Service @Controller）@Repository用于注解dao层，在daoImpl类上面注解@ModelAttribute、@SessionAttributes传递和保存数据，在不同的模型（model）和控制器之间共享数据@PathVariable、@RequestParam@PathVariable获取请求路径上的变量值@RequestParam用来获得静态的URL请求入参 spring注解时action里用到@RequestHeader、@CookieValue@RequestHeader可以把Request请求header部分的值绑定到方法的参数上。@CookieValue可以把Request header中关于cookie的值绑定到方法的参数上@RequestParam, @RequestBody@RequestParam用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容，提交方式GET、POST@RequestBody常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容，例如application/json,application/xml等