前言

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

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

问题描述:

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

追了一下后端服务器日志,发现后端报空指针异常,报错信息如下所示:
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. emoji表情等特殊字符处理和存储的两个方案

    方案1.改数据库配置 使之支持emoji表情等特殊字符,小公司或者个人开发还好,大公司用此方案代价较大. 以mysql为例,改配置方法参考:https://blog.csdn.net/u0107373 ...

  2. Sql server 删除重复记录的SQL语句

    原文地址:https://www.cnblogs.com/luohoufu/archive/2008/06/05/1214286.html 在项目开发过程中有个模块日清表页面数据重复,当时那个页面的数 ...

  3. 为了拿捏 Redis 数据结构,我画了 40 张图(完整版)

    大家好,我是小林. Redis 为什么那么快? 除了它是内存数据库,使得所有的操作都在内存上进行之外,还有一个重要因素,它实现的数据结构,使得我们对数据进行增删查改操作时,Redis 能高效的处理. ...

  4. Codeforces 1422F - Boring Queries(树套树)

    upd on 2021.9.5:昨天的那个版本被 2-tower 卡爆了,故今天重发一个. Codeforces 题面传送门 & 洛谷题面传送门 没往"每个数最多只有一个 \(> ...

  5. vector.erase();vector.clear();map.erase();

    vector::erase()返回下一个iter: STL中的源码: //清除[first, last)中的所有元素 iterator erase(iterator first, iterator l ...

  6. FESTUNG 模型介绍 — 2. 对流问题隐式求解

    FESTUNG 模型介绍 - 2. 对流问题隐式求解 1. 控制方程 对流问题的控制方程为 \[\partial_t C + \partial_x u^1 C + \partial_y u^2 C = ...

  7. python12类

    self 表示类里面的对象的引用 python一般不需要去解决内存管理,解释器会进行自动给回收 #类鱼类之间空格两行,前面的函数里面也是两行,类里面的方法个一行 class Cat(object): ...

  8. wireshatk_teach

    wireshark抓包新手使用教程 Wireshark是非常流行的网络封包分析软件,可以截取各种网络数据包,并显示数据包详细信息.常用于开发测试过程各种问题定位.本文主要内容包括: 1.Wiresha ...

  9. A Child's History of England.34

    'Prince!' said Fitz-Stephen, 'before morning, my fifty and The White Ship shall overtake [超过, 别和take ...

  10. GPU随机采样速度比较

    技术背景 随机采样问题,不仅仅只是一个统计学/离散数学上的概念,其实在工业领域也都有非常重要的应用价值/潜在应用价值,具体应用场景我们这里就不做赘述.本文重点在于在不同平台上的采样速率,至于另外一个重 ...