分类 | 分类描述 |
---|---|
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
状态码 | 描述 |
---|---|
200 | 请求成功 |
400 | 客户端请求的语法错误 |
401 | 未授权 |
404 | 请求的网页不存在 |
408 | 请求超时 |
414 | 请求的 URI 过长 |
500 | 服务内部异常 |
502 | 错误网关 |
503 | 服务器超时 |
http请求报文组成: 1、请求行:一般由请求方法+url+http协议版本字段组成。 GET /data/info.html HTTP/1.1 (HTTP/1.0:一次连接只能执行一次请求和响应后就关闭了,没有HOST字段; HTTP/1.1 一次连接可以多次请求和响应,且必须要有HOST字段); 2、请求头:Accept、Accept-Encoding、Use-Agent、Content-Type、Content-Length(Post请求必有)、Host、if-modify-since、Cookie、Connection等组成; 3、空行:标志请求头结束; 4、请求数据:若方法字段是GET,则此项为空,没有数据;若方法字段是POST,则通常来说此处放置的就是要提交的数据。
POST方法请求报文如下,它的请求行URL段中一般是没有参数的,参数放在了报文体中。而GET方法的参数直接置于请求行URL中,报文体则为空。
HTTP响应报文: 1、响应行:包含http协议版本+状态码+描述 HTTP/1.1 200 OK; 2、响应头:描述服务器的基本信息:Allow(服务器支持哪些请求方法)、Content-Encoding(如果request.getHeader("Accept-Encoding")支持gzip,则返回gzip压缩后编码格式的文档)、Content-Type、Content-Length、Expires、Last-Modified(只有改动时间迟于指定时间(If-Modified-Since)的文档才会返回,否则返回一个304(Not Modified)状态)、Set-Cookie、Transfer-Encoding:告诉浏览器数据的传送格式、Date等; 3、空行:发送回车符+换行符,标志响应头的结束; 3、响应体:如果是纯数据就是返回纯数据,如果请求的是HTML页面,那么返回的就是HTML代码,如果是JS就是JS代码,如此之类。
HTTP协议解读:HTTP协议-HTTP响应报文 - 掘金
请求方法:
POST:用于传输实体的主题
GET:获取资源,请求访问已经被URI识别的资源
PUT:传输文件,自身不带验证机制,任何人都可以上传文件,存在安全性问题
DELETE:删除文件。同样不带验证机制,存在安全性问题。
请求头字段
Host
Accept:客户端支持接受响应类型
text/plain
text/csv
text/html
text/xml
application/javascript
application/json
application/zip
application/xml
multipart/form-data
image/xxx
Accept-Charset:请求编码
utf-8
Accept-Encoding
gzip
zip
Accept-Language:
Cookie:jsessionid
Cache-Control:响应返回的内容在客户端是否被缓存
no-cache
Connection:
Last-Modified:
Content-Type:
Content-Lengh:
Date
请求头
请求方式+URI+协议版本
请求首部字段:
实体首部字段
其他
请求体
空行
请求数据
http 报文首部 | ProcessOn免费在线作图,在线流程图,在线思维导图
请求方法+URL+协议版本
GET | POST | |
---|---|---|
请求参数 | 多个参数以&连接 HTTP协议对URL长度没有限制,但是实际浏览器和服务器存在规范限制,建议最多1KB |
数据放在Body中 请求长度无限制 |
数据类型 | 只接受ASCII字符 | 无限制 |
参数位置 | 请求头 | 请求体 |
参数获取 | 请求可以携带Body,但是通过Body不能保证数据一定被接收到 | 无限制 |
安全性 | 提交的数据缓存在URL上,页面会被浏览器缓存 明文传输 |
请求不会缓存,除非手动设置 可明可密 |
数据传输 | 产生一个TCP数据包,将请求头和请求体一次性发送。等待响应 | 产生两个TCP数据包 发送请求头,获取响应 发送请求体,等待响应 |
服务器限制:
Nginx 的配置参数为large_client_header_buffers
Tomcat 的请求配置参数为maxHttpHeaderSize
浏览器限制:
IE浏览器对URL的长度现限制为2048字节。
360极速浏览器对URL的长度限制为2118字节。
Firefox(Browser)对URL的长度限制为65536字节。
Safari(Browser)对URL的长度限制为80000字节。
Opera(Browser)对URL的长度限制为190000字节。
Google(chrome)对URL的长度限制为8182字节。
操作方式 | 数据位置 | 明文密文 | 数据安全 | 长度限制 | 应用场景 |
---|---|---|---|---|---|
GET | HTTP包头 | 明文 | 不安全 | 长度较小 | 查询数据,无修改 |
POST | HTTP正文 | 可明可密 | 安全 | 支持较大数据传输 | 修改数据 |
HTTP | HTTPS | |
---|---|---|
传输内容 | 超文本传输,明文形式 | 具有安全性的ssl加密传输协议 |
端口 | 80 | 443 |
安全性 | 连接简单 | 连接相对复杂,需要C/S之间证书校验 |
区别:傻傻分不清之 Cookie、Session、Token、JWT - 掘金
HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息 ;不同端口下的cookie可以共享 ,cookie的跨域可以理解为跨域名 ,domain可以设置域名,只要二级域名相同就可以共享,与端口无关。
Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。
Token:关于access_token&refresh_token的作用?access_token与refresh_token之为什么要用refresh_token刷新不重新获取access_token?_Soul_Niz_Kingdom-CSDN博客_为什么要刷新token
概念: 令牌, 是访问资源的凭证。
我有几个疑问。第一你的refresh token和token有什么不一样?生成都一样吗?第二 refresh token存客户端还是服务端?第三 存服务端是不是人人都能拿着去换新的 安全性?我觉得refresh这个东西只是一个最大时间 就允许你在这段时间刷新token 超过了就去登录。
第 一 问: refresh_token是用来刷新access_token的,而access_token是接口调用凭据;第二, 三问: refresh_token存于数据库或者其他安全的地方,在内部调用及使用,保证其安全;最后,你觉得是你觉得,我要我觉得;开个玩笑,因为access_token的有效期是2个小时,这2个小时不会因为你使用它就为你续期,2个小时后你就得重新登录一遍,对用户的体验极差,所以就需要refreshh_token刷新去为其续期,保证用户在连续使用超过2个小时后不用重新登录;如有不对,请纠正;
先说一下去refresh_token安全的问题,取refresh_token是在access_token未过期的时候取出来刷新access_token续命用的,然后如果account_token过期了的话,需要重新登录,用code去获取account_token,这个时候refresh_token也是新的了,所以不存在access_token过去取refresh_token的问题。
若access_token已超时,那么进行refresh_token会获取一个新的access_token,新的超时时间; 2. 若access_token未超时,那么进行refresh_token不会改变access_token,但超时时间会刷新,相当于续期access_token。 然后我已经试验过了,refresh_token在执行刷新之后是不会变的;
1、 refresh一次相当于给access_token两个小时 2 、可以在数据库存储每个登录用户的refresh_token,写定时调度,不到两小时的时候调用一次进行续期 。
JWT与Token的区别:JWT和token的区别及优缺点 - 涛子17180 - 博客园 ;token**需要查库验证token** 是否有效,而JWT**不用查库或者少查库,直接在服务端进行校验,并且不用查库**。因为用户的信息及加密信息在第二部分payload和第三部分签证中已经生成,只要在服务端进行校验就行,并且校验也是JWT自己实现的。
JWT是json web token缩写。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。
cookie分为二种
1,以文件方式存在硬盘空间上的长期性的cookie:登录时选择记住状态,就是将登录的信息以文件的形式存储在客户端的硬盘上。
2,停留在浏览器所占内存中的临时性的cookie
session更安全:存在于服务端保密性强,
ArrayList:底层是数组结构,查询快:每个数据有对应的index好定位;增删慢:删除一个元素后,后面的数据要移动,量大的话就很慢;
LinkedList:底层是链表结构,查询慢:无索引,增删快:删除元素,只需要改变指针到新的元素即可。两者都不是线程安全的,可以用Vector,读多写少用CopyOnWriteArrayList,读少写多用Collections.synchronizedList()方式
List的是允许重复元素,有序,Set是不能有重复元素,无序
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
先判断hash值是否相同,再判断equal是否相同。
Queue队列:先进先出,
add/put:添加元素,如果满了,add就报异常,put会阻塞;
remove/poll:移除并返回队列头部的元素,队列为空,remove则抱异常,poll返回null;
element/peek:返回队列头部的元素,队列为空,element抱异常,peek返回null。
Stack栈:后进先出,最上面是栈顶,pop、push、empty、peek(查看栈顶的对象,但不移除它)
集合比数组好处是长度能变,分为单列(List、Set)和双列集合(Map),排序:Collections.sort()升序,
//降序 Collections.sort(list, new Comparator
遍历:for循环、forEach、set.iterator() ;while(iterator.hasNext())
Map的遍历:for(Map.Entry
HashMap底层是Entry数组+单链表(JDK1.8前)的结构
数组的初始容量是16,负载因子是0.75,当容量大于12时会自动扩容
存放键值对,键不能相同、不能为null,存放规则是根据键的hashcode值与Entry数组长度取模得到index,位置是随机的,而遍历时nextNode方法的index是自增的,所以无序(与 LinkedHashMap 的区别:LinkedHashMap 是HashMap的子类,底层是双向链表,遍历是nextNode方法中调用是index.after(),所以是有序的,有插入和访问顺序。)
当有hash冲突时,会将元素添加到链表中,JDK1.8后当链表长度大于8且hash桶的容量大于64时会转为红黑树,长度小于6又会变成链表
线程不安全的,所以查询速度快
Vector列表、HashTable、ConCurrentHashMap:将hash表分成16个segment,采用锁分段技术、Stack
普通队列是先进先出,优先队列中存入的每项数据都附带一个数值,与进入的次序无关,以优先级最高的先出;
应用场景:当电商出秒杀时,会有很多用户下单,此时即使会员用户在队列中排在普通用户的后面,但可以根据优先级先给会员创建订单。
QueuecustomerPriorityQueue = new PriorityQueue<>(7, idComparator); public static Comparator idComparator = new Comparator (){ @Override public int compare(Customer c1, Customer c2) { return (int) (c1.getId() - c2.getId()); } };
保证程序的健壮性:对可预测的一些可能性问题,提供了处理任何意外或异常情况的方法。通常使用try-catch-finally、try-with-resource以及throws等方式进行处理。
NullPointerException: 空指针异常
ClassCastException: 类型强制转换异常
ClassNotFoundException:类找不到异常
ArrayIndexOutOfBoundsException: 数组下标越界异常
ArithmeticException:算术运算异常
NumberFormatException: 数字格式异常
IOExeption:IO异常
FileNotFoundException:文件找不到异常
InterruptedException:中断异常
SQLException:SQL语句异常
单例模式
懒汉式
双重检查锁定(double-checked locking) + volatial:因为singleton = new Singleton()
不是原子性操作,可能会被重排序。volatial 禁止重排序并且保证了变量的可见性。
** * 功能描述 * 单例模式:因为被static修饰的类变量在类被加载时就会创建,所以饿汉模式中当类只是调用其他方法时就频繁的创建类会造成损耗,故用懒汉模式 * 懒汉式-双检锁volatile+synchronized * * @author cWX1112617 * @date 2021/12/14 * @since 2021-12-14 */ public class SingleClass { /** * 多线程并发引起的安全性问题:当多个线程访问共享数据,而cpu切换线程是随机的。 * 并发编程面临的三个问题:原子性、可见性、时序性。 * volatile:可以解决可见性和时序性,不能解决原子性 */ private static volatile SingleClass singleClass; private SingleClass(){} public SingleClass getInstance() { if (singleClass == null) { synchronized (SingleClass.class) { if (singleClass == null) { /* 对象的创建不是原子性操作,加载有三个步骤 * 1.在堆中开辟地址空间 * 2.在空间中初始化SingleClass对象 * 3.将singleClass引用指向地址空间 * 但是JVM的指令重排序,由于2.3不存在数据依赖性,可能顺序为1-3-2, * 当执行1-3时singleClass已经不为null,等到出锁会对后面线程判断失误, * 所以应该在SingleClass加上volatile,保证时序性不会出现重排序 * */ singleClass = new SingleClass(); } } } return singleClass; } }
饿汉式:在类加载的时候就完成了初始化,所以类加载比较慢
静态初始化
静态内部类
public class SingleClass2 { private static class SingleClassHolder { private static final SingleClass2 singleClass2 = new SingleClass2(); } private SingleClass2(){} public SingleClass2 getInstance() { return SingleClassHolder.singleClass2; } }
简单工厂模式
抽象工厂模式
观察者模式
S(单一职责原则):
O(OCP,开闭原则):
L(LSP,里氏替换原则):
L(LOD,Law of Demeter,迪米特法则):
I(ISP,接口隔离原则):
D(依赖倒置原则):
用例图、类图、时序图、状态图
1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁,不会死锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
ReentrantLock获取锁 三种方式:
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
synchronized:是互斥锁:一次只能允许一个线程进入被锁住的代码块;是内置锁/监视器锁,是一种锁的标记,锁住的是对象,对象有自己的对象头,里面有很多信息,其中一个信息标示是被哪个线程持有
重入锁:
public class Widget { // 锁住了 public synchronized void doSomething() { ... } } public class LoggingWidget extends Widget { // 锁住了 public synchronized void doSomething() { System.out.println(toString() + ": calling doSomething"); super.doSomething(); } }
当线程A进入到LoggingWidget的doSomething()方法时,此时拿到了LoggingWidget实例对象的锁。
随后在方法上又调用了父类Widget的doSomething()方法,它又是被synchronized修饰。
那现在LoggingWidget实例对象的锁还没有释放,进入父类Widget的doSomething()方法还需要一把锁吗?
不需要的!
因为锁的持有者是“线程”,而不是“调用”。线程A已经是有了LoggingWidget实例对象的锁了,当再需要的时候可以继续“开锁”进去的!
这就是内置锁的可重入性。记住,持有锁的是线程。
corePoolSize:核心线程数
maxPoolSize:最大线程池
keeyALiveTime:失效时长
timeUnit:时间单位
queue:工作队列
threadFactory:线程工厂
rejectedExecutionHandler:回收策略
只有一个线程处理所有请求,新来的任务均存入无界队列中排队
来一个请求新建一个线程
CAS:Compare and Swap, 翻译成比较并交换。
CAS指令在Intel CPU上称为CMPXCHG指令,它的作用是将指定内存地址的内容与所给的某个值相比,如果相等,则将其内容替换为指令中提供的新值,如果不相等,则更新失败。这一比较并交换的操作是原子的,不可以被中断。初一看,CAS也包含了读取、比较 (这也是种操作)和写入这三个操作,和之前的i++并没有太大区别,是的,的确在操作上没有区别,但CAS是通过硬件命令保证了原子性,而i++没有,且硬件级别的原子性比i++这样高级语言的软件级别的运行速度要快地多。虽然CAS也包含了多个操作,但其的运算是固定的(就是个比较),这样的锁定性能开销很小。
从内存领域来说这是乐观锁,因为它在对共享变量更新之前会先比较当前值是否与更新前的值一致,如果是,则更新,如果不是,则无限循环执行(称为自旋),直到当前值与更新前的值一致为止,才执行更新。
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
1.取得当前值
2.计算+1后的值
3.如果当前值没有被覆盖的话设置那个+1后的值
4.如果设置没成功, 再从1开始
生命周期(lifecycle)主要包括
clean
resources
complie
install
pacakge
testResources
testCompile
deploy
阶段 | 处理 | 描述 |
---|---|---|
验证 validate | 验证项目 | 验证项目是否正确且所有必须信息是可用的 |
编译 compile | 执行编译 | 源代码编译在此阶段完成 |
测试 Test | 测试 | 使用适当的单元测试框架(例如JUnit)运行测试。 |
包装 package | 打包 | 创建JAR/WAR包如在 pom.xml 中定义提及的包 |
检查 verify | 检查 | 对集成测试的结果进行检查,以保证质量达标 |
安装 install | 安装 | 安装打包的项目到本地仓库,以供其他项目使用 |
部署 deploy | 部署 | 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程 |
模块 | 描述 | 备注 |
---|---|---|
maven clean | 清理 | |
maven test | 测试 | |
maven compile | 编译 | |
maven package | 打包 | |
maven install | 安装项目到本地仓库 | |
mvn deploy | 发布项目到远程仓库 | |
mvn dependency:tree | 显示maven依赖树 | |
mvn dependency:list | 显示maven依赖列表 |
mvn compile:将源码编译成字节码
mvn package:编译结果打包成Jar包或WAR包
mvn install:将Jar包和War包部署到本地maven仓库
mvn deploy:将Jar包和War包布署到本地maven仓库和远程maven私服仓库
一个免费的开放源代码的Web应用服务器,属于轻量级WEB应用服务器
默认端口:8080
修改配置文件 server.xml
JUnit 是一个回归测试框架,用于单元测试。
单元测试工具,常用注解:
@Test:修饰方法,指定需要测试的方法(public void method())
timeout:测试时间超时限制
expected:测试是否它抛出了指定的异常
@Before:修饰public 方法,在执行每个测试方法之前执行,执行多次
@BeforeClass:修饰public static method,执行所有测试方法之前执行,只执行一次
@After:修饰public method,在执行每个测试方法之后执行,执行多次
@AfterClass:修饰public static method修饰方法,在所有测试结束之后执行,只执行一次
@Ignore:修饰public method,忽略测试,注释的测试方法将不会被执行
@RunWith:修改类,运行器。
Junit4ClassRunner.class:Junit 默认自带
SpringJUnit4ClassRunner.class:Spring相关
SpringRunner.class:SpringBoot 相关的
Suite.class:测试套件,将多个相关的测试类视为一个套件一起测试,通过@Suite.SuiteClasses({xxx.class,xxx.class})指定需要测试的类
套件中的所有测试类的测试方法都会执行,但是Suite类本身用例则不会执行了
Parameterized.class:使用多个参数组合多次执行同一个测试用例
@Parameters:注释的公共的静态方法,返回一个对象的集合(数组)来作为测试数据集合
测试类需要有构造函数
一个 public static 方法被@Parameters标注,只能返回Iterable类型或数组类型的数据
执行顺序:@BeforeClass -> @Before -> @Test -> @After -> @AfterClass
@BeforeClass | @Before | |
---|---|---|
定义个数 | 只能包含一个 | 多个,执行顺序不确定 |
修饰方法 | 必须声明为public static | 必须声明为public 并且非static |
执行次数 | 在类中只运行一次 | 在每个测试方法之前都会运行一次 |
执行顺序 | 优先@Before | 晚于@BeforeClass,早于@Test |
类:Test+测试类。首字母大写的驼峰命名。
方法:test+用例操作_状态
DT:Developer Test,(别称LLT,LOW LEVER TEST),包括
单元测试(Unit Test)
集成测试(Integration Test)
模块系统测试(Module System Test)
系统集成测试(BBIT)
Junit
Mockito:
JMockit
Jmock需要在执行前记录期望行为(expectations),显得很繁琐,而Mockito通过在执行后校验哪些函数已经被调用,消除了对期望行为(expectations)的需要,API非常简洁