HTTP1.1
1、无状态、明文传输,不安全
2、长连接,超时服务端主动断开
3、管道传输,减小响应时间
问题:没有解决响应的队头阻塞
HTTP2.0
1、头部压缩:多个请求,头部相似,会消除重复部分
2、二进制格式:头部信息和数据信息都采用二进制格式,头部帧、数据帧,增加数据传输效率
3、并发传输:使用Stream ID来区分不同的HTTP请求,通过多路复用一条tcp连接,实现了http并发传输的效果,性能比http1.1高了很多
4、服务器主动推送资源
问题:一旦发生丢包,就会阻塞住所有的 HTTP 请求
HTTP3.0
基于 UDP 的 QUIC 协议
基于TCP的HTTP协议:四元组(源 IP、源端口、目的 IP、目的端口)
QUIC 协议:通过连接 ID 来标记通信的两个端点
HTTP
1、超文本传输协议,明文传输,不安全
2、连接简单,TCP三次握手后即可进行传输
3、端口:80
HTTPS
1、引入SSL/TLS安全协议(传输层和网络层之间),加密传输
2、不仅需要TCP三次握手,还需要SSL/TLS握手过程
3、端口:443
4、需要向CA申请数字证书
HTTP是无状态协议,可通过cookie、session保存用户状态,cookie是在客户端存储,session是在服务端存储
cookie:服务端收到HTTP请求,在**浏览器(客户端)**的响应头中添加cookie信息(保存sessionId或token),用于保存用户登录信息
客户端每发一次新请求,浏览器都会将之前保存的cookie信息通过cookie请求头再发给服务器,此时浏览器发出之后,就有可能被拦截,不安全
session:在服务端记录用户的登录信息
**token:**由服务端生成,并发给客户端
token:客户端发起登录请求,服务端验证通过后,生成全局唯一Token,绑定用户信息(value),并将Token作为key存入Redis中
多端登录:(secretId:客户端的唯一标识)
使用Token获取用户信息
1、根据request获取userId
2、根据userId获取用户信息
// 根据token获取用户信息
@GetMapping("getMemberInfo")
public R getMemberInfo(HttpServletRequest request) {
// 调用jwt工具类方法,根据request对象,获取头信息,返回用户id
String memberId = JwtUtils.getMemberIdByJwtToken(request);
// 查询数据库,根据用户id,获取用户信息
UcenterMember member = memberService.getById(memberId);
return R.ok().data("userInfo", member);
}
可使用Redis设置验证码5分钟有效时间
@RestController
@CrossOrigin
@RequestMapping("/edumsm/msm")
public class MsmController {
@Autowired
private MsmService msmService;
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 发送短信
@GetMapping("send/{phone}")
public R sendMsm(@PathVariable String phone) {
// 1. 先从redis中获取验证码,如果能获取直接返回
String code = redisTemplate.opsForValue().get(phone);
if (! StringUtils.isEmpty(code)) {
return R.ok();
}
// 2. 如果获取不到,再进行阿里云发送
// 生成随机的值,传递给阿里云发送
code = RandomUtil.getFourBitRandom();
Map<String, Object> param = new HashMap<>();
param.put("code", code);
// 调用service发送短信的方法
boolean isSend = msmService.send(param, phone);
if (isSend) {
// 发送成功,把发送成功验证码放到redis里,并设置有效时间
redisTemplate.opsForValue().set(phone, code, 5, TimeUnit.MINUTES);
return R.ok();
} else {
return R.error().message("短信发送失败");
}
}
}
只需要登录一次,即可访问互相信任的系统
三种常见方式
1、session广播机制实现(基本不用了)
session复制
2、使用cookie+redis 实现
redis:在key:生成唯一随机值(ip、id等),在value:用户数据
cookie:把redis里面生成的key值放到cookie中
3、使用token实现
令牌
token:按照一定的规则生成字符串,字符串可以包含用户信息
1.在项目某个模块进行登录,登录之后,按照规则生成字符串,将用户信息包含在字符串里,最后返回字符串
2.再访问项目其他模块,每次访问在地址栏带着生成的字符串,在访问模块里获取地址栏字符串,根据字符串获取用户信息。如果可以获取到,就是登录
session默认过期时间:30min
session、redis、token都可以设置过期时间
JWT令牌:按照规定好的规则,使用JWT可以直接生成字符串,包含用户信息(JWT头+用户信息+签名哈希)
对于集群,如果 session 保存在其中一台机器上,就会涉及到数据不一致的问题,可以使用MySQL或Redis来存储用户信息
常用:基于redis实现共享session登录
不安全
补充HashMap和ConcurrentHashMap相关知识
ConcurrentHashMap
不建议在使用for循环对ArrayList进行元素遍历删除
如果必须使用for循环进行元素遍历删除操作,可以使用迭代器来实现
怎么实现?有没有其他方式?
整个项目使用一个统一的异常处理方式
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(BaseException.class)
public ResponseEntity<?> handleAppException(BaseException ex, HttpServletRequest request) {
//......
}
@ExceptionHandler(value = ResourceNotFoundException.class)
public ResponseEntity<ErrorReponse> handleResourceNotFoundException(ResourceNotFoundException ex, HttpServletRequest request) {
//......
}
}
@ControllerAdvice:aop思想的一种实现,你告诉我需要拦截规则,我帮你把他们拦下来,具体你想做更细致的拦截筛选和拦截之后的处理,你自己通过@ExceptionHandler实现
Exception
不可以,error是不能处理的错误
不可检测异常,运行时异常
类加载时,先判断当前类是否被加载过,已加载直接返回,否则才尝试加载
加载首先会把请求委派给父类加载器的loadClass()处理,即传送到顶层的启动类加载器 BootstrapClassLoader 。父类加载器无法处理时才自己处理。父类加载器为null,使用启动类加载器作为父类加载器
自定义加载器,需要继承 ClassLoader,重写 ClassLoader 类中的 findClass() 方法即可,无法被父类加载器加载的类最终会通过这个方法被加载
不知道执行多久就用join,主线程等待子线程结束之后再执行,这个时候不需要sleep,直接 join 的话,返回的就一定是子线程执行完毕的结果了
String a在堆中,“ABC”在字符串常量池中
补充String相关知识
不会,最左匹配原则
索引失效:
1、使用左、左右模糊查询 like %xx,like %xx%
2、对索引列做计算、函数、类型转换操作
3、联合索引未遵循最左匹配原则
4、WHERE子句中,ON前是索引列,ON后不是索引列
假设有一个(a, b, c)联合索引,它的存储顺序是先按 a 排序,在 a 相同的情况再按 b 排序,在 b 相同的情况再按 c 排序
等于b不符合,等于a符合
不能,因为索引的 B+树结构是按照索引列的值从小到大排序的,而左模糊匹配的查询条件中,通配符 “%” 出现在了左侧,导致无法按照索引列的值有序查找