转载

包教不包会系列-跨域

包教不包会系列-跨域

前言

这段时间心态上有点放松了,收收心了

昨天晚上无聊,把 SpringBoot 的官方文档看了一遍,对于一个英语渣来说,真难得

想学的东西很多,但是时间不允许啊。前端 Or 后端,早日决断吧 :sob::sob::sob:,太难了

跨域

跨域解决的方案有好几种,掌握 Cors 就行了,别的了解下就可以了

什么情况下回跨域呢?

跨域是指从一个源去请求另一个源的资源,浏览器基于完全考虑并遵循同源策略,禁止跨域访问。但是我们可以通过一些手段(jsonp 或者 Cors)来实现跨域。

简单理解:当 url 中的协议/域名/端口 不同时,就产生了跨域。

跨域只会发生在浏览器中,后端服务之间的接口调用是没有跨域一说的

包教不包会系列-跨域

跨域的解决方案?

  • nginx 反向代理,将请求的接口全部转发就行了
  • jsonp
  • cors

nginx 反向代理解决跨域

location /api {
    proxy_pass  http://192.168.202.50:8082/;
}

匹配 url 中以 /api 开头的路径
http://192.168.202.50:8081/api -->  http://192.168.202.50:8082
http://192.168.202.50:8081/api/users/2 --> http://192.168.202.50:8082/users/2 
复制代码

来自 8081 的页面请求了 /api/users/2 代理接口,nginx 经过路径匹配,找到对应的 location 处理,将其转发到实际接口 /8082/users/2,从而规避跨域。

jsonp 解决跨域

jsonp 解决跨域了跨域,但是也有自己的缺陷,服务端需要对跨域和非跨域做不同的处理。

$.ajax({
    url:'http:192.168.202.50:8082/users/2'
    type:'get',
    dataType:'jsonp',
    success(data){},
    error(error){}
});
复制代码

在发送请求的时候,浏览器会多携带一个 callback 参数

// 服务端使用 SpringBoot 处理
@GetMapping(value = "/users/2")
public String domainAjaxJsonpNoCookie(HttpServletRequest request){
    HashMap<Object, Object> ret = new HashMap<>(16);
    ret.put("key1","ajax-jsonp-no-cookie");
    ret.put("key2", Math.random());
    
    String callback = request.getParameter("callback");
    
    String retString= JSON.toJSONString(ret);
    
    // 跨域处理,当不是跨域的时候,这样处理ajax 会拿不到正确的数据
    retString=callback+"("+retString+")";
    return retString;
}
复制代码

Cors

推荐看下 阮一峰-跨域资源共享 CORS 详解

cors 解决跨域,只需要服务端配合就行,浏览器会自动判断是否跨域,添加 origin 请求头,服务端只需要添加请求头 Access-Control-Allow-Origin:* (这样 cookie 不能携带) Access-Control-Allow-Origin: http://192.168.202.8080 (这样可以携带 cookie)

SpringBoot 使用注解 @CrossOrigin

// 注解可以添加到类上或者方法上
@CrossOrigin(value = "http://192.168.202.50:8080",allowCredentials="true")
@GetMapping(value = "/domain/cors/cookie")
public Map domainCorsCookie(HttpServletRequest request, HttpServletResponse response){
    Cookie[] cookies = request.getCookies();
    HashMap<Object, Object> ret = new HashMap<>(16);
    if(cookies!=null){
        for (Cookie cookie1 : cookies) {
            if (Objects.equals("corsCookie",cookie1.getName())) {
                ret.put(cookie1.getName(),cookie1.getValue());
            }
        }
    }
    return ret;
}
复制代码

CorsFilter 过滤器

@Configuration
public class MyCorsConfig {
    @Autowired
    private AppProperties appProperties;
    /**
     * 配置 cors 过滤器
     */
    private CorsConfigurationSource getMyCorsConfigurationSource(String path){
        CorsConfiguration config = new CorsConfiguration();
        // 设置跨域允许携带 cookie
        config.setAllowCredentials(true);
        // 配置允许那些 网址跨域
        config.setAllowedOrigins(appProperties.getAllowIp());
        // 配置多长时间不用跨域预检请求
        config.setMaxAge(1800L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration(path, config);
        return source;
    }

    @Bean
    public FilterRegistrationBean  registrationCorsFilterBean(){
        FilterRegistrationBean filterRegistrationBean =new FilterRegistrationBean();
        // 所有的请求都允许跨域
        CorsConfigurationSource myCorsConfigurationSource = getMyCorsConfigurationSource("/**");
        CorsFilter corsFilter = new CorsFilter(myCorsConfigurationSource);
        filterRegistrationBean.setFilter(corsFilter);
        return filterRegistrationBean;
    }
}

@Configuration
@ConfigurationProperties(prefix = "app.cors")
@Data
public class AppProperties {
    private List<String> allowIp;
}
复制代码

遇到的坑

  • 跨域的时候 cookie 不能携带

这个需要客户端和服务端同时配合,服务端才能拿到 cookie

$.ajax({
    url:'http:192.168.202.50:8082/users/2'
    type:'get',
    dataType:'jsonp',
    
    // 告诉浏览器要携带 cookie
    xhrFields: {
        withCredentials: true
    },
    success(data){},
    error(error){}
});
复制代码
// Access-Control-Allow-Origin:http://192.168.202.8080,
// 这个属性需要设置对应的地址,设置 * 不行
// allowCredentials  服务端配置允许携带 cookie
@CrossOrigin(value = "http://192.168.202.50:8080",allowCredentials="true")
复制代码
// 配置过滤器属性,Access-Control-Allow-Origin 和 allowCredentials
 private CorsConfigurationSource getMyCorsConfigurationSource(String path){
        CorsConfiguration config = new CorsConfiguration();
        // 设置跨域允许携带 cookie
        config.setAllowCredentials(true);
        // 配置允许那些 网址跨域
        config.setAllowedOrigins(appProperties.getAllowIp());
        // 配置多长时间不用跨域预检请求
        config.setMaxAge(1800L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration(path, config);
        return source;
    }
复制代码

cookie Path 设置错误

包教不包会系列-跨域

上图只能看到当前页面可以访问的 cookie

查看域名下所有的 cookie

包教不包会系列-跨域

进入下级页面即可看到 cookie 选项

可以查看某个域名下的全部 cookie

包教不包会系列-跨域
Cookie retCookie=new Cookie("serverCookie",String.valueOf(Math.random()));
        retCookie.setMaxAge(10000000);
        retCookie.setHttpOnly(true);
        // 跨域设置 cookie 必须设置 path
//        retCookie.setPath("/");
        response.addCookie(retCookie);
复制代码

当你没有设置 Path 的时候,默认设置请求接口路径。

比如说,你登陆接口(/login)返回 cookie(name=login),cookie 没有设置 path,会自动给你设置 /login。而当你请求/users/2 的接口的时候,是不会携带 cookie(name=login)。

原文  https://juejin.im/post/5d5fe00d6fb9a06b0202cb93
正文到此结束
Loading...