前言

前两周在把兄弟公司的几个服务部署到我们公司测试环境服务器的时候又遇到了不少问题,因为是前后端分离的项目,所以这次也同样遇到了跨域问题,解决方式也跟上一回的不一样,这里就再来分析记录一下。

登录验证码在本地获取正常但部署到服务器报空指针异常问题

问题描述:

登录页面的验证码,在本地运行项目的时候可以正常获取和显示,但部署到测试环境服务器上验证码图片却无法显示出来,如下图所示:

追了一下后端服务器日志,发现后端报空指针异常,报错信息如下所示:
java.lang.NullPointerException: null
at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)
at sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:219)
at sun.awt.FontConfiguration.init(FontConfiguration.java:107)
at sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:774)
at sun.font.SunFontManager$2.run(SunFontManager.java:431)
at java.security.AccessController.doPrivileged(Native Method)
at sun.font.SunFontManager.(SunFontManager.java:376)
at sun.awt.FcFontManager.(FcFontManager.java:35)
at sun.awt.X11FontManager.(X11FontManager.java:57)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:83)
at java.security.AccessController.doPrivileged(Native Method)
at sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)
at java.awt.Font.getFont2D(Font.java:491)
at java.awt.Font.access$000(Font.java:224)
at java.awt.Font$FontAccessImpl.getFont2D(Font.java:228)
at sun.font.FontUtilities.getFont2D(FontUtilities.java:180)
at sun.java2d.SunGraphics2D.checkFontInfo(SunGraphics2D.java:669)
at sun.java2d.SunGraphics2D.getFontInfo(SunGraphics2D.java:830)
at sun.java2d.pipe.GlyphListPipe.drawString(GlyphListPipe.java:50)
at sun.java2d.SunGraphics2D.drawString(SunGraphics2D.java:2928)
at com.lanmei.common.ImageUtil.createimage(ImageUtil.java:77)
......
跟踪代码后发现,在绘制验证码图片时使用了Graphics画布,Graphics在绘制验证码字符时,需要先设定字体,如下所示:
g.setFont(new Font("DejaVu Sans", Font.CENTER_BASELINE, 18));
这就是问题点所在,在windows系统上,运行这行代码是完全没问题的,因为windows系统自带这种字体,可是我们测试环境服务器上运行的linux镜像系统并没有这种字体,所以就报空指针异常了。

解决办法:构建一个带有指定字体的基础镜像

构建了一个自带“DejaVu Sans”字体的openjdk镜像,使用该镜像来运行我们的程序,就能正常获取和显示登录验证码了,如下图所示:

注意:关于构建这个镜像,有两种方式可以选择,一种是创建一个跟原来一样没有“DejaVu Sans”字体的基础openjdk镜像,然后再执行添加相应字体的命令,对应的Dockerfile编写方式如下:
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY ${JAR_FILE} app.jar
RUN apk add --update ttf-dejavu fontconfig
EXPOSE 8086
ENTRYPOINT ["java","-jar","/app.jar"]
使用这种方式的缺点在于每次构建镜像的时候都要花很多时间去下载我们所需要的字体,效率很低。
另一种方式则是先在我们自己公司用于存放镜像的服务器上专门构建一个带有“DejaVu Sans”字体的openjdk镜像,然后用它来运行我们的项目,这样一来能够满足功能需求,二来是直接从我们自己的镜像服务器上拉取镜像、速度也会快很多。

前后端不同域导致session丢失问题

问题描述:

输入的登录验证码没有错,可是却一直报:验证码错误,登录失败!
在后端打了一些日志后,发现如下信息:

这里我们登录验证码的完整校验逻辑是这样的:用户请求登录页面时,调用后端生成验证码的接口,后端生成一个验证码返回给前端并将验证码字符串缓存在浏览器session中,用户输入登录信息后,后端根据用户输入的验证码与用户缓存在浏览器session中的验证码字符串进行比对,若一致则校验通过,否则校验失败。
根据日志可以判断,这里session中缓存的验证码丢失了,导致后端获取不到。
按F12键使用开发者工具查看获取验证码的请求响应,可以看到如下信息:
根据上图可以得知,后端尝试将验证码缓存到浏览器session中时,由于前后端不同域导致该操作被拦截了。

解决办法:通过前端nginx设置同域代理转发请求

在nginx配置文件中添加如下配置:
location /hello-sso-service {
proxy_pass http://xxx.xxx.xxx.xxx:8080/hello-sso-service;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
将与hello-sso-service相关的接口请求代理转发到对应的后端服务接口,这样缓存验证码到session的操作就不会被拦截了。
更新代码配置后,重新进行登录,后端服务就能从session中获取到相应的验证码了,如下图所示:
 
关于前后端不同域,这次我其实还遇到了另外一个小问题:在退出登录时,需要跳转到前端登录页面并且在url中携带一些参数请求后端一个接口,也就是说,跳转的地址组成结构为“前端ip:端口+对应的后端接口”。
针对这个问题,我也是使用nginx进行了如下代理:
location /v1 {
proxy_pass http://xxx.xxx.xxx.xxx:8081/v1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

总结

这段时间在部署这些新服务的过程中,学习了不少前后端服务部署的知识,尤其对于前后端跨域问题有了很深刻的体会。所谓“同域”,就是“协议+主机+端口”都相同,反之则称之为“跨域”。

解决“跨域”问题较常见的办法就是使用nginx进行反向代理设置,如上文中提到的两个例子,通过代理使前后端“同域”,就可以解决相应的session设置失败及接口请求不通等问题。

获取登录验证码失败及前后端不同域导致session丢失问题分析记录的更多相关文章

  1. 使用nginx反向代理处理前后端跨域访问

    本文主要解决:使用nginx反向代理处理前后端跨域访问的问题 1.何为跨域访问? 以下类型为跨域访问 1)不同域名间访问 www.zuiyoujie.com和www.baidu.com 2)同域名不同 ...

  2. java结合node.js非对称加密,实现密文登录传参——让前后端分离的项目更安全

    前言   在参考互联网大厂的登录.订单.提现这类对安全性操作要求较高的场景操作时发现,传输的都是密文.而为了目前项目安全,我自己负责的项目也需要这方面的技术.由于,我当前的项目是使用了前后端分离技术, ...

  3. 用Nginx代理请求,处理前后端跨域

    自从前端spa框架出现后,都是前后端分离开发了.我们在开发的时候难免会遇到跨域的问题.跨域这种问题解决的方法基本都是在服务端实现的.以java为例,我知道的有3种方法处理跨域: 1.使用 @Cross ...

  4. 简单设置,解决使用webpack前后端跨域发送cookie的问题

    最近用vue来做项目,用webpack来做前端自动化构建.webpack-dev-server会在本地搭建一个服务器,在和后端调试的时候,就会涉及到跨域的问题. 刚开始时,没有用vue-cli来构建项 ...

  5. 前后端跨域 _ cross domain

    1. 解决跨域既可以从前端, 也可以从后端. 参考好的网络资源: http://www.cnblogs.com/vajoy/p/4295825.html

  6. vue解决前后端跨域问题

    1/在config中index.js中 找到proxyTable在里面添加如下代码 proxyTable: { '/api': { target: 'https://api.douban.com/v2 ...

  7. springboot2.1.3 配置前后端跨域问题

    很简单,创建一个配置类即可,如下: package com.app.gateway.common.config; import org.springframework.context.annotati ...

  8. springboot 前后端分离开发 从零到整(三、登录以及登录状态的持续)

    今天来写一下怎么登录和维持登录状态. 相信登录验证大家都比较熟悉,在Javaweb中一般保持登录状态都会用session.但如果是前后端分离的话,session的作用就没有那么明显了.对于前后端分离的 ...

  9. Vue Springboot (包括后端解决跨域)实现登录验证码功能详细完整版

    利用Hutool 基于Vue.ElementUI.Springboot (跨域)实现登录验证码功能 前言 一.Hutool是什么? 二.下面开始步入正题:使用步骤 1.先引入Hutool依赖 2.控制 ...

随机推荐

  1. [loj3364]植物比较

    结论:设$b_{i}$满足该限制,则$a_{i}$合法当且仅当$\forall i\ne j,a_{i}\ne a_{j}$且$\forall |i-j|<k,[a_{i}<a_{j}]= ...

  2. [loj3339]美食家

    令$f[i][j]$表示第$i$个时刻走到点$j$的最小时间,暴力的$dp$复杂度为$o(tm)$ 如果没有限制,由于$w\le 5$,记录前5个时刻的状态即可求出当前状态,用矩阵乘法可优化到$o(n ...

  3. jpa生成uuid

    使用jpa可以生成uuid,但是我直接添加数据没有id值会报错,只在程序中有效,如果直接修改数据库需要手动填写,另外长度不要乱填 ,之前填了200,找了半天才找到原因. package com.jav ...

  4. git分支切换的一些问题

    关于git切换分支后该分支的修改会在另一个分支里面一起修改的问题 修改分支后导致稳定版的主分支里面的文件连带修改. 原因:切换分支前原分支没有提交,导致新建的文件或者文件夹,没有纳入版本管理,所以会被 ...

  5. SpringCloud微服务实战——搭建企业级开发框架(二十五):实现多租户多平台短信通知服务

    目前系统集成短信似乎是必不可少的部分,由于各种云平台都提供了不同的短信通道,这里我们增加多租户多通道的短信验证码,并增加配置项,使系统可以支持多家云平台提供的短信服务.这里以阿里云和腾讯云为例,集成短 ...

  6. 【POJ2018】【实数域上的二分】【dp】

    传送门:http://poj.org/problem?id=2018: 大概题意是求一个正整数数列 A 的平均数最大 长度不小于 L 的子段 我们可以二分答案 判定是否有一个长度不小于L的子段 平均数 ...

  7. [yLOI2018] 锦鲤抄

    先思考图上是\(tag\)的特殊情况. 考虑我们按拓扑序反过来操作,就可以得到我们任意想要的顺序. 那么我们把所有的图都缩点操作,那么我们只需要考虑一个联通分量里就行了. 一个联通分量最后只会剩下一个 ...

  8. 洛谷 P6031 - CF1278F Cards 加强版(推式子+递推)

    洛谷题面传送门 u1s1 这个推式子其实挺套路的吧,可惜有一步没推出来看了题解 \[\begin{aligned} res&=\sum\limits_{i=0}^ni^k\dbinom{n}{ ...

  9. [R] ignore.case区分大小写参数

    字符串操作的函数(如contains),很多都包含ignore.case参数,默认是T,即不分大小写,稍不注意就会掉坑里,最好的习惯是下意识地加入这个参数. 举个例子: 我要选择An的列,就用下面这个 ...

  10. Python查找最长回文暴力方法

    查找最长回文子串 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为1000. 例如1: 输入: "babad" 输出: "bab" ...