多益网络历年面经整理(不全)

你在项目中负责的模块,怎么做的,后台协议用的啥

博客园:

JWT

登录使用JWT技术

jwt 可以生成 一个加密的token,做为用户登录的令牌,当用户登录成功之后,发放给客户端。

请求需要登录的资源或者接口的时候,将token携带,后端验证token是否合法。

jwt 有三部分组成:A.B.C

A:Header,{"type":"JWT","alg":"HS256"} 固定

B:playload,存放信息,我自己存放是用户id+过期时间,可以被解密,不能存放敏感信息

C: 签证,A和B加上秘钥 加密而成,只要秘钥不丢失,可以认为是安全的。

jwt 验证,主要就是验证C部分 是否合法。

Redis存储对象

没有进行redis的序列化配置。而是使用阿里巴巴的json来进行转化。

后期打算进行配置一下。

/**  * Created by 酥梨 on 2021/6/28 17:10  */ @Configuration public class RedisConfiguration {  /**  * 重写Redis序列化方式,使用JSON方式 * 当我们的数据存储到Redis的时候,我们的键和值都是通过Spring提供的Serializable序列化到Redis的。  * RedisTemplate默认使用的是JdkSerializationRedisSerializer  * StringRedisSerializer默认使用的是StringRedisSerializer  *  * Spring Data JPA 为我们提供了下面的Serializable(6种)  * GenericToStringSerializer,Jackson2JsonRedisSerializer  * JacksonJsonRedisSerializer,JdkSerializationRedisSerializer  * OxmSerializer,StringRedisSerializer  * 再次我们将自己配置RedisTemplate并定义Serializer  */   @Bean  public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){  RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();  redisTemplate.setConnectionFactory(redisConnectionFactory);   //创建一个JSON的序列化对象  GenericJackson2JsonRedisSerializer Jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();  //设置value的序列化方式json  redisTemplate.setValueSerializer(Jackson2JsonRedisSerializer);  //设置key为String的序列化方式  redisTemplate.setKeySerializer(new StringRedisSerializer());  //设置hash key的序列化方式  redisTemplate.setHashKeySerializer(new StringRedisSerializer());  redisTemplate.setHashValueSerializer(Jackson2JsonRedisSerializer);  redisTemplate.afterPropertiesSet();  return redisTemplate;  } }
https和http的区别,能说出https具体的步骤吗
  • HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。

  • 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。

  • HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。

  • http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。

  • HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

HTTPS建立过程

  • 1.首先客户端先给服务器发送一个请求

  • 2.服务器发送一个SSL证书给客户端,内容包括:证书的发布机构、有效期、所有者、签名以及公钥

  • 3.客户端对发来的公钥进行真伪校验,校验结果为真则使用公钥对对称加密算法以及对称密钥进行加密

  • 4.服务器端使用私钥进行解密并使用对称密钥加密确认信息发送给客户端

  • 5.随后客户端和服务端就使用对称密钥进行信息传输

说一下常见的web开发安全问题
  1. SQL注入

简介: 由于程序中对用户输入检查不严格,用户提交一段查询字符串,改变SQL的结果。获得某些他想得知的数据 。

分析:参数检查不合格,导致提交的非法数据当做语句的一部分来执行。SQL语句使用。

预防:

  • 严格限定参数类型,服务端进行参数校验

  • 采用参数化查询的方式,不能拼串

  • 数据库加固(数据库权限需要管理)

  1. 跨站请求伪造CSRF

简介: 窃取或操纵客户会话和 cookie,它们可能用于模仿合法用户,从而使黑客能够以该用户身份查看或变更用户记录以及执行事务

分析: 应用程序使用的认证方法不充分

预防:

  • 使用一次性令牌

  • 验证图片

简介: 点击劫持是一种视觉欺骗的攻击手段。

分析: 用户在登陆 A 网站的系统后,被攻击者诱惑打开第三方网站,而第三方网站通过 iframe 引入了 A 网站的页面内容,用户在第三方网站中点击某个按钮(被装饰的按钮),实际上是点击了 A 网站的按钮。

预防:JS

内连接与外连接

内连接,也被称为自然连接,只有两个表相匹配的行才能在结果集中出现。返回的结果集选取了两个表中所有相匹配的数据,舍弃了不匹配的数据。由于内连接是从结果表中删除与其他连接表中没有匹配的所有行,所以内连接可能会造成信息的丢失。内连接语法如下:

select fieldlist from table1 [inner] join table2 on table1.column = table2.column


外连接不仅包含符合连接条件的行,还包含左表(左连接时)、右表(右连接时)或两个边接表(全外连接)中的所有数据行。SQL外连接共有三种类型:左外连接(关键字为LEFT OUTER JOIN)、右外连接(关键字为RIGHT OUTER JOIN)和全外连接(关键字为FULL OUTER JOIN)。外连接的用法和内连接一样,只是将INNER JOIN关键字替换为相应的外连接关键字即可。


客户端实现实时推送消息

使用scoket长连接进行服务器主动推送,客户端不断轮询请求服务器获取最新消息 。

mongdb了解吗

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在提供可扩展的高性能数据存储解决方案。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

最近了解哪些新技术

准备学习docker,因为之前需要在Nginx上部署前端,有点搞不懂。

内存泄露和内存溢出了解吗?怎么查看内存泄露?

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。 内存泄露分类

  1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。

  2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。

  3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。

  4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

如何查看内存泄露

内存泄漏一般不会造成程序崩溃,所以比较隐晦,但是发现内存泄露的方法也很简单,就是让程序运行一段时间,然后查看内存先后变化,通过任务管理器(windows)或者top(unix/linux)来监控某个进程的内存变化是比较方便的,有些程序的内存泄露比较小,但是发现它的内存泄露也都是时间问题。这里列出一个内存泄漏的程序的内存变化时间图,可以看出其内存占用总体上是呈递增的 。


数据库sql语句的安全性
  1. 防止SQL注入(参数校验,SQL语句不要直接拼装,对特殊字符进行转意)

  2. 最小权限原则,严格限制数据库权限,构建不同的权限账户

  3. 运行出错的时候,不要全部返回给前端。防止泄露服务器与数据库的相关信息

拦截器
  1. 通过代理的方式去调用

  2. AOP的实现

  3. 实现了HandlerInterceptor接口,并实现了preHandle方法

  4. 需要在配置文件中进行配置

  5. 方***在执行controller方法(handler)之前进行执行

/** * 1. 需要判断,请求的路径是否为 HandlerMethod(controller方法) * 2. 判断token是否为空,如果为空 未登录 * 3. 如果token是非空,进行登录验证 LoginService的checkToken * 4. 如果认证成功 放行即可 * 5. 在放行之前,需要将用户数据放入到UserThreadLocal中,以便在线程中随时直接可以使用。 * 6. 在返回的时候,需要清除UserThreadLocal中的数据,因为弱引用导致的内存泄露问题。 */  @Component @Slf4j public class LoginInterceptor implements HandlerInterceptor {   @Autowired  private LoginService loginService;   @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  //在执行controller方法(handler)之前进行执行  /**  * 1. 需要判断,请求的路径是否为 HandlerMethod(controller方法)  * 2. 判断token是否为空,如果为空 未登录  * 3. 如果token是非空,进行登录验证 LoginService的checkToken  * 4. 如果认证成功 放行即可  */  if (!(handler instanceof HandlerMethod)){  //handler 可能是 RequestResourcehandler  // springboot 程序 访问静态资源 默认是classpath下的static目录去查询  return true;  }  String token = request.getHeader("Authorization");   log.info("========================request start==========================");  String requestURI = request.getRequestURI();  log.info("request uri:{}",requestURI);  log.info("request method:{}",request.getMethod());  log.info("token :{}",token);  log.info("========================request end==========================");   if (StringUtils.isBlank(token)){  Result result = Result.fail(ErrorCode.NO_LOGIN.getCode(), "未登录");  response.setContentType("application/json;charset=utf-8");  response.getWriter().print(JSON.toJSONString(result));  return false;  }  SysUser sysUser = loginService.checkToken(token);  if (sysUser == null){  Result result = Result.fail(ErrorCode.NO_LOGIN.getCode(), "未登录");  response.setContentType("application/json;charset=utf-8");  response.getWriter().print(JSON.toJSONString(result));  return false;  }  //到这里全部检验完毕,放行  //希望在controller中,直接取得sysUser  UserThreadLocal.put(sysUser);  return true;  }   @Override  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {  //如果不删除UserThreadLocal中的用完的信息,会有内存泄露的风险  UserThreadLocal.remove();  }  } 
多线程锁与死锁

sync和lock

  • 两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象

  • 避免死锁就是破坏造成死锁的,若干条件中的任意一个

    • 互斥: 一个资源每次只能被一个线程使用

    • 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。

    • 不剥夺条件:线程已获得的资源,在未使用完之前,不能强行剥夺。

    • 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。

HashMap的底层数据结构

数组+链表+红黑树

static class Node<K,V> implements Map.Entry<K,V> {  final int hash;  final K key;  V value;  java.util.HashMap.Node<K,V> next;
解决哈希冲突
  1. 开放定址法

    所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入

  2. 再哈希法

    再哈希法又叫双哈希法,有多个不同的Hash函数,当发生冲突时,使用第二个,第三个,….,等哈希函数 计算地址,直到无冲突。虽然不易发生聚集,但是增加了计算时间。

  3. 拉链法

  4. 建立公共溢出区

    这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表

指针与引用

指针是一个变量,存储的是一个地址,指向内存的一个存储单元;

引用是原变量的一个别名,跟原来的变量实质上是同一个东西。

  • 强引用

  • 软引用

    一般用于缓存。有用但是没有必要的对象。

  • 弱引用

    描述非必须对象。ThreadLocal的用的就是弱引用。因此可能导致的内存泄露。

  • 虚引用

    给垃圾回收期发消息

Java的缺点

使用虚拟机运行,运行速度较慢

不能和底层打交道,不支持底层操作(UnSafe)

启动时间慢

排序算法哪些稳定
  • 插入排序

  • 冒泡排序

  • 归并排序

TCP三次握手+四次挥手

建立连接 - 三次握手

由于一个完整的TCP连接需要经过三次握手才能完成,这里把三次握手之前的连接都称之为半开连接


最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。

❶ TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;

❷ TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这时报文首部中的同步序号SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。

❸ TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。

❹ TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。

❺ 当服务器收到客户端的确认后也进入ESTABLISHED(已确认)状态,此后双方就可以开始通信了。

socket函数


从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

总结:客户端的connect在三次握手的第二个次返回,而服务器端的accept在三次握手的第三次返回。

断开连接 - 四次挥手


数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。

❶ 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

❷ 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

❸ 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

❹ 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

❺ 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗ *∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

❻ 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

socket函数


说一下网站开发时候,注意什么?

OOP说一下

数据库事务

隔离级别以及会发生的问题

可重复读级别下,防止了幻读怎么做?

SQL题

1-1000,找到质数+个位数的和是偶数

到公司需要转型

加班怎么看?

抽象类与接口的异同?

JVMGC算法

项目中高并发怎么解决的

怎么限流的

用过explain吗?用来干嘛了?

最近学过那些技术

经常逛哪些网站


#多益网络##面经#
全部评论

相关推荐

3 22 评论
分享
牛客网
牛客企业服务