低调人的gravatar头像
低调人 2018-07-11 22:06:09
SpringBoot学习之实现前后端分离的跨域访问(Nginx)

研发项目中,Nginx反向代理,可以解决跨域无权和Session丢失的问题,十分方便。下面我们以前后端分离为案例,展开Nginx的使用教程。

一. 配置和启动Nginx

下载地址

Nginx下载传送门:Nginx Stable Version Download

注意事项:下载之后,记得解压到全英文路径,避免中文路径导致Nginx启动失败。

修改配置

打开nginx.conf ,清空配置项,然后将下面的配置信息原封不动拷贝进去:

 

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    #前端页面服务器
    server {
        #监听端口和域名
        listen       7000; 
        server_name  localhost;

        #添加头部信息
        proxy_set_header Cookie $http_cookie;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        #添加拦截路径和代理地址
        location /api/ {              
               proxy_pass http://localhost:8080/;  #注意:使用代理地址时末尾记得加上斜杠"/"。      
        }
        
        #添加拦截路径和根目录
        location / {
               root   html/hehe;  #注意:使用"/"拦截全路径的时候记得放在最后。
               index  index.html index.htm;  #index表示首页 
        }           
        
    }
}

 

快速启动

在Windows 环境中:

  • 快速启动Nginx:右键管理员模式,运行nginx.exe。
  • 快速关闭Nginx:在nginx主目录,添加关闭Nginx的命令。

其中结束Nginx.bat的具体内容如下:

taskkill /f /im nginx.exe

SpringBoot学习之实现前后端分离的跨域访问(Nginx)

 

二. 部署前端页面

前后端分离后,可以直接将静态资源(例如前端页面)部署到Nginx的html目录。这里我们在$nginx_home/html目录下创建一个名为hehe的文件夹,并添加一个页面(index.html)用于跨域访问测试,index页面内容如下:

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Page Index</title>
</head>
<body>
<h2>前台系统7000</h2>
<p id="info1"></p>
<p id="info2"></p>
</body>

<script src="js/jquery.js"></script>
<script>
        $.ajax({
            url: 'http://localhost:7000/api/user/login/verifyCode',
            type: "POST",
            success: function (data) {
                //1.获取验证码
                $("#info1").html("跨域访问成功:verifyCode:" + data);
                //2.核对验证码
                $.ajax({
                    url: 'http://localhost:7000/api/user/login/checkVerifyCode',
                    type: "POST",
                    success: function (data) {
                        $("#info2").html("跨域访问成功:checkVerifyCode:" + data);
                    }
                });
            },
            error: function (data) {
                $("#info1").html("跨域失败!!");
            }
        });
</script>

</html>

三. 启动后端系统

首先在POM文件添加Web依赖,然后编写控制层,提供对外的访问接口。默认启动端口是8080.

package com.hehe;

@SpringBootApplication
@RestController
@RequestMapping("/user/login/*")
public class SpringBootNginxApplication {
    //在拦截器打印访问URL
    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(new HandlerInterceptor() {
                    @Override
                    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
                        if(response.getStatus()/100>=4){
                            System.err.println("访问URL:"+request.getAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE));
                        }else {
                            System.out.println("访问URL:"+request.getRequestURI());
                        }
                    }
                });
            }
        };
    }

//提供验证码

@RequestMapping("verifyCode")

public String verifyCode(HttpServletRequest request) {

        request.getSession().setAttribute("verifyCode", "N7GX");

        return request.getSession().getId() + ":" + request.getSession().getAttribute("verifyCode");

}

//核对验证码

@RequestMapping("checkVerifyCode")

public String checkVerifyCode(HttpServletRequest request) {

        return request.getSession().getId() + ":" + request.getSession().getAttribute("verifyCode");

}

public static void main(String[] args) {

        SpringApplication.run(SpringBootNginxApplication.class, args);

}

}

 

 

 

四. 测试跨域访问

打开浏览器,访问 http://localhost:7000/api/user/login/verifyCode ,可以看到后台获取的Session和第一次生成的验证码。如图:

SpringBoot学习之实现前后端分离的跨域访问(Nginx)

 

打开浏览器,访问 http://localhost:7000/api/user/login/checkVerifyCode ,可以看到后台获取的Session和第二次取出的验证码。

由上图可以看到,跨域访问成功,并且Session没有丢失。

五. Nginx跨域总结

Nginx VS CORS

简单来说,Nginx是间接跨域,而CORS则实现了直接跨域。Nginx的反向代理“欺诈了”浏览器,所以浏览器和服务器都认为是同源访问,所以Session不会丢失。(PS:如果发生跨域访问,服务器会每次都创建新的Session,所以才造成了前后端分离的Session丢失问题。) 至于CORS这种跨域机制的安全性和灵活性更高,但需要自己解决跨域访问Session丢失的问题,通常情况可以采用Session+Redis来实现Session共享。)

Nginx跨域实现过程:

第1步:http://localhost:7000/index.html

第2步:http://localhost:7000/api/user/login/verifyCode

第1步是打开页面,第2步是在这个页面发起AJAX请求,并且请求的域名端口均与当前访问页面相同,属于同源操作,所以浏览器不会报出跨域禁止的错误。

第3步:http://localhost:8080/user/login/verifyCode

第3步是本案例最为关键的一步,真正的跨域操作由Nginx的proxy_pass进行完成,并成功将验证码信息以代理的身份返回给浏览器,让浏览器处于同源访问后台的错觉。打开F12可以看到代理服务器:

SpringBoot学习之实现前后端分离的跨域访问(Nginx)

 

关于proxy_pass 斜杠"/' 的坑

通常情况下,建议大家在代理地址末尾加上"/" ,表示转发后就是proxy_pass直接拼接映射路径。

Nginx代理效果:

转发前URL:http://localhost:7000/api/user/login/verifyCode

转发后URL:http://localhost:8080/hehe/user/login/verifyCode

 

server {
        listen       7000; 
        server_name  localhost;
        
        #正确示范: 末尾加斜杠"/"
        location /api/ {              
               proxy_pass http://localhost:8080/hehe/; 
        }
                    
    }

如果代理地址末尾没有加斜杠的话,表示转发后也是proxy_pass直接拼接映射路径,但是,拼接的时候会少了个"/",这样会引发访问路径错误。

Nginx代理效果:

转发前URL:http://localhost:7000/api/user/login/verifyCode

转发后URL:http://localhost:8080/heheuser/login/verifyCode

 

server {
        listen       7000; 
        server_name  localhost;
        
        #错误示范: 末尾无斜杠
        location /api/ {              
               proxy_pass http://localhost:8080/hehe; 
        }
                    
    }

为了更方便大家,看到在Nginx调整了proxy_pass有无斜杠的区别,楼主在控制台打印了每次请求访问的URL地址,这样更加清晰:

 

具体做法:关闭Nginx 将代理地址修改为:proxy_pass http://localhost:8080/hehe ,然后启动Nginx,在浏览器访问http://localhost:7000/api/user/login/verifyCode,然后查看控制台打印的URL信息。清楚的看到了因为少了斜杠而导致拼接成错误路径,如下:

 

SpringBoot学习之实现前后端分离的跨域访问(Nginx)

测试完成了

 


打赏

已有5人打赏

已注销用户的gravatar头像 人间蒸发的gravatar头像 lhrce的gravatar头像 丶附耳聆听的gravatar头像 最代码官方的gravatar头像
最近浏览
17693522332  LV1 2020年11月7日
wkc  LV21 2020年6月28日
qaz7225277 2020年4月23日
暂无贡献等级
zhanghongwei  LV3 2020年4月21日
已注销用户  LV34 2020年4月1日
人间蒸发  LV23 2020年3月22日
下载狂魔 2020年1月16日
暂无贡献等级
艾克斯 2019年11月16日
暂无贡献等级
ivancolin  LV9 2019年11月7日
abc1534 2019年7月14日
暂无贡献等级
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友