Java 跨域问题的解决手段

1. 为什么会有跨域

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

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

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

协议 主机 端口
http www.baidu.com 80

Java 跨域问题的解决手段_第1张图片

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

2. 什么是跨域

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

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

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

3. DEMO准备

项目1:端口号8080
Java 跨域问题的解决手段_第3张图片
一个页面

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>

简单按钮请求:但是请求的是 另外一个服务器的资源
Java 跨域问题的解决手段_第4张图片

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,这个时候就会发生跨域问题。如下:
Java 跨域问题的解决手段_第5张图片

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";
    }
}

Java 跨域问题的解决手段_第6张图片

同样可以使用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,看文字不如看张图
Java 跨域问题的解决手段_第7张图片
同样可以实现跨域访问
Java 跨域问题的解决手段_第8张图片

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;
        }

}

实现跨域
Java 跨域问题的解决手段_第9张图片
这里需要注意的是,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,通过天然支持跨域的标签

你可能感兴趣的:(工作随手记,java,nginx,vue)