Java 跨域问题的解决手段

1. 为什么会有跨域

浏览器出于对于浏览网页安全性问题的考虑,引入的同源策略。

什么是同源策略,听着很官方,简单一幅图说明:

同源指的是URL地址三要素(协议,主机,端口号)必须不变

协议主机端口
httpwww.baidu.com80

在这里插入图片描述

例如我客户端访问80端口的百度,只要协议,和端口不变访问
http://www.baidu.com:80/aaa/bbb 满足同源策略,访问京东同样如此。

2. 什么是跨域

同样如上图,如果出现了在百度页面可以访问京东的页面,这中间就出现了跨域问题。

这种问题 会引起什么问题呢?

其实在正常的界面访问直接一般不会出现问题,但是如果是涉及到访问一些需要登录后访问的信息时,这样就会存在安全隐患,例如,同样看图
在这里插入图片描述
很明显,可以正常访问到界面2的内容,但是如果界面2的内容属于敏感信息呢,我们不需要被访问到!!!

3. DEMO准备

项目1:端口号8080
在这里插入图片描述
一个页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <script src="/js/axios.min.js"></script>
    <script src="/js/vue.min.js"></script>
</head>
<body>

<button id="btn" @click.prevent = "click">点击按钮,测试跨域</button>

</body>

<script>
    new Vue({
        el:"#btn",
        methods:{
            click(){
                axios.get("http://localhost:80/jd/index");
            }
        }

    });
</script>
</html>

简单按钮请求:但是请求的是 另外一个服务器的资源
在这里插入图片描述

URL地址是:http://localhost:80/jd/index

项目2:端口号 80

@RestController
@RequestMapping("/jd")
public class IndexController {


    @GetMapping("/index")
    public String index(){
        return "index";
    }
}

两个都是基于SpringBoot构建,如果通过项目1的请求,去访问项目2的controller,这个时候就会发生跨域问题。如下:
在这里插入图片描述

4. 解决手段

4.1 设置Access-Control-Allow-Origin

修改项目2的controller

@RestController
@RequestMapping("/jd")
public class IndexController {


    @GetMapping("/index")
    public String index(HttpServletResponse response){
        //运行项目1访问:只需要协议 + 主机 + 端口
        response.addHeader("Access-Control-Allow-Origin","http://localhost:8080");
        //允许所有访问
//        response.addHeader("Access-Control-Allow-Origin","*");


        //扩展:
        // 域间请求的最大等待最时间(单位s)
        //1. 表示每10s发送一次域间请求,不足10s就不需要发送域间请求,提高访问效率
//        response.addHeader("Access-Control-Max-age","10");
//
//        //2.只允许GET请求
//        response.addHeader("Access-Control-Allow-Method","GET");
//
//        //3.请求头携带xxx参数
//        response.addHeader("Access-Control-Allow-Headers","xxx");
        return "index";
    }
}

在这里插入图片描述

同样可以使用SpringBoot自带的注解@CrossOrigin进行配置

@GetMapping("/index")
    @CrossOrigin
    public String index(HttpServletResponse response){
        return "index";
    }
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
    /** @deprecated */
    @Deprecated
    String[] DEFAULT_ORIGINS = new String[]{"*"};
    /** @deprecated */
    @Deprecated
    String[] DEFAULT_ALLOWED_HEADERS = new String[]{"*"};
    /** @deprecated */
    @Deprecated
    boolean DEFAULT_ALLOW_CREDENTIALS = false;
    /** @deprecated */
    @Deprecated
    long DEFAULT_MAX_AGE = 1800L;

    @AliasFor("origins")
    String[] value() default {};

    @AliasFor("value")
    String[] origins() default {};

    String[] originPatterns() default {};

    String[] allowedHeaders() default {};

    String[] exposedHeaders() default {};

    RequestMethod[] methods() default {};

    String allowCredentials() default "";

    long maxAge() default -1L;
}

具体配置细节可网上查询 CrossOrigin介绍

4.2 借助RestTemplate实现远程调用

项目1:安排RestTemplate

@Configuration
public class RPCConfig {

    @Autowired
    private RestTemplateBuilder restTemplateBuilder;

    @Bean
    public RestTemplate restTemplate(){
        return restTemplateBuilder.build();
    }
}

我们转换思路:原先从项目1的index.html访问项目2,现在转换成从项目1的html访问到项目1的controller,再从项目1的controller转而访问项目2的controller,将返回数据再次返给项目1的html,看文字不如看张图
在这里插入图片描述
同样可以实现跨域访问
在这里插入图片描述

4.3 借助Nginx实现反向代理

将我们的项目1的index.html放入nginx静态服务器中,并和nginx处于同一个监听端口

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <script src="/js/axios.min.js"></script>
    <script src="/js/vue.min.js"></script>
</head>
<body>

<button id="btn" @click.prevent = "click">点击按钮,测试跨域</button>

</body>
<script>
    new Vue({
        el:"#btn",
        methods:{
            click(){
                axios.get("http://localhost:81/jd/index").then(response=>{
                    console.log(response.data);
                });
            }
        }

    });
</script>
</html>

nginx配置文件


worker_processes  1;

events {
    worker_connections  1024;
}


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

    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       81;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;


        location /jd {
        #反向代理项目2的地址,只要包含/jd开头的都转发到http://localhost:80
			proxy_pass http://localhost:80;
        }

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

}

实现跨域
在这里插入图片描述
这里需要注意的是,nginx必须监听的是,要代理的端口,这样才可以实现跨域。

通过正则表达式修改Nginx映射规则

location /jd {
	rewrite ^/jd/(.*)$ /$1 break;
	proxy_pass http://localhost:80;
}

可以做到代理到80的任意URL,如我们将项目2的controller地址改为
http://localhost/jd/index 也可以正常访问

4.4 jsonp技术

jsonp属于比较老的技术了,运用的是一些天然支持跨域的标签特性,进行函数回调的过程。

举个例子:

在项目1 的index.htm,通过天然支持跨域的标签<script>来实现跨域,<script>请求项目2的

@RestController
@RequestMapping("/jd")
public class IndexController {


    /**
     * 方法2:借助restTemplate 远程调用
     * @param response
     * @return
     */
    @GetMapping("/index")
    public String index(HttpServletResponse response){
        return "cross('es-jd-index')";
    }
}

index.html

<script>
    function cross(data) {
        console.log(data);
    }
</script>

<script src = 'http://localhost:80/jd/index'></script>

来进行函数的回调执行,这种方法现在也不常用,比较常用的是Nginx来实现跨域!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值