史上最全跨域问题解决方案
  P9EFSeIq9hyq 2023年11月02日 76 0

一、为什么会有跨域问题

出现跨域的根本原因:浏览器的同源策略不允许非同源的URL之间进行资源的交互。

那么,什么是同源?概念:如果两个页面的协议、域名和端口都相同,则这两个页面具有相同的源。

不同源,就属于跨域。

史上最全跨域问题解决方案_jsonp

二、跨域解决方案

一般来讲,有JSONP和CORS两种方式,JSONP兼容性好,但是只支持GET数据请求,不支持POST请求;CORS不兼容某些低版本的浏览器但是它支持GET和POST请求。

此外,因为httpclient不依赖浏览器,所以也可以做为一种解决方案。

1、JSONP

JSONP的实现原理:由于浏览器收同源策略的限制,网页无法通过Ajax请求非同源的接口数据,但是script标签不受浏览器同源策略的影响,可以通过src属性请求非同源js脚本。简而言之,JSONP的实现原理就是通过<script>标签的src属性,请求跨域的数据接口,并通过函数调用的形式,接收跨域接口响应回来的数据。

这里以Jquery中的方式为例:

<body>
    <script>
        $(function() {
            $.ajax({
                url: 'http://www.test.top:8001/api/jsonp?name=xiaoming&age=18',
                dataType: 'jsonp',
                success: function(res) {
                    console.log(res);
                }
            })
        })
    </script>
</body>

如果想自定义参数及回调函数,代码如下:

<body>
    <script>
        function cb() {
            console.log('111');
        }
    </script>
    <script>
        $(function() {
            $.ajax({
                url: 'http://www.test.top:8001/api/jsonp?name=xiaoming&age=18',
                dataType: 'jsonp',
                jsonpCallback: 'cb',
                success: function(res) {
                    console.log(res);
                }
            })
        })
    </script>
</body>

2、CORS

下面给出了若干解决方案,但是本质都是一样的,都是围绕HTTP 头字段(Access-Control-Allow-Origin)展开的。

(1)新建配置类,通过CorsFilter来实现

package com.zy.demo.controller;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorseConfig {

    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);

    }
}

(2)新建配置类,实现WebMvcConfigurer接口,在其addCorsMappings()方法中添加映射路径、允许源、请求方法和允许头信息等设置

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
 
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://domain1.com", "http://domain2.com")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("*")
    }
}

(3)使用@CrossOrigin注解方式

package com.zy.demo.controller;
import com.zy.demo.entity.custom.UserLoginParam;
import com.zy.demo.entity.table.TUser;
import com.zy.demo.service.TUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private TUserService tUserService;
    
    @CrossOrigin(origins = "*")
    @RequestMapping("/login")
    public Object loginUser(UserLoginParam cUser){
        Map<String, Object> result = new HashMap<String, Object>();
        System.out.println(cUser);
        if("admin".equals(cUser.getCUsername())&&"123456".equals(cUser.getCPwd())){
            result.put("code",200);
            result.put("msg","登录成功");
            result.put("token","admin");
            return result;
        }

        result.put("code",500);
        result.put("msg","登录失败");
        return result;
    }
}

(4)添加过滤器

package com.zy.demo.controller;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "CORSFilter", urlPatterns = {"/*"})
@Order(value = 1)
@Configuration
public class AccessControlAllowOriginFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        chain.doFilter(req, response);
    }

    public void init(FilterConfig filterConfig) {

    }

    public void destroy() {

    }

}

(5)Nginx代理方式,使用add_header指令,该指令可以用来添加一些头信息

Access-Control-Allow-Origin: 直译过来是允许跨域访问的源地址信息,可以配置多个源的地址(多个源用逗号分隔),也可以使用 *代表所有源

Access-Control-Allow-Methods:直译过来是允许跨域访问的请求方式,值可以为 GET POST PUT DELETE...,可以全部设置,也可以根据需要设置,多个用逗号分隔

史上最全跨域问题解决方案_cors_02

(6)使用Gateway网关

Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其 不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监 控/埋点、限流等。

添加配置类:

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

3、httpclient方式,不经过浏览器

http原生请求:

public class HttpTest {
    @Test
    public void test1() throws Exception {
     String url = "https://www.badu.com";
        URL url1 = new URL(url);
        //url连接
        URLConnection urlConnection = url1.openConnection();
        HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection;
        //获取httpURLConnection输入流
        InputStream is = httpURLConnection.getInputStream();
        //转换为字符串
        InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
        BufferedReader br = new BufferedReader(reader);
        String line;
        //将字符串一行一行读取出来
        while ((line = br.readLine())!= null){
            System.out.println(line);
        }
    }
}

实际项目使用中一般会进行封装。

结语:几种方式介绍完毕,可能还有其他方式,原理都差不多,大家下去可以自己研究一下。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读