跨域问题解决

跨域问题是当前网站,通过ajax请求,访问其他网站资源会出现的问题,报错一般是报CORS相关内容,因为浏览器针对跨域请求,会默认走CORS解决方案,如果服务器没有对应的配置,就会报CORS相关的响应头Access-Control-Allow-Origin缺失异常

同源策略:

同源策略是浏览器的一种安全策略,简单来讲就是当前资源网站访问其他资源,浏览器就会进行判别,如果不是同源的资源,就会对本次请求返回的内容进行拦截,并在控制台抛出错误信息(注:浏览器只会对返回内容进行拦截,不会对请求拦截,也就是说从请求服务器,但服务器响应返回这个流程还会正常执行)。

浏览器判断是否是同源资源的方法:协议、域名、端口号,这三个如果有任何一个不同,都会判定为非同源资源。

如下情况会导致步骤二调用后端接口跨域问题

跨域问题解决方案

JSONP

早期的解决方式,但只能用于解决get请求,现在几乎不用,这里不做细化。

proxy

服务代理,此方式是在浏览器和所有的目标资源服务之间放一台代理服务器,如NGINX服务器,这样浏览器直接访问的都是NGINX服务,浏览器和NGINX不存在跨域了,至于通过NGINX转发后的地址不同,服务器之间不会有同源策略,自然就不会存在跨域问题。

注意:不要认为链路中有nginx就不存在跨域问题,必须全部的资源都用同一nginx做代理访问,如果出现下图中的访问index.html不采用代理,调用经过nginx代理的/test/getuserInfo也一样会出现跨域问题,因为index.html的h5服务和nginx服务域名不同。这种情况经常出现在前端开发在本地启动项目,然后访问测试环境接口进行调试。如果要满足这种使用情况,需单独在nginx配置CORS或者在后端服务上配置CORS

CORS

CORS是w3c的一个标准,全称是“跨域资源共享”(Cross-origin resource sharing)

CORS需要浏览器和服务器共同支持才能完成,目前,所有的主流浏览器都默认支持CORS,IE浏览器不能低于IE10;服务器需要自行设置才支持。

浏览器对跨域请求会进行特殊处理,加请求头Origin或者发一次options请求(预检请求),根据响应头中的信息判断服务器是否允许此次跨域请求。

nginx配置CORS

在配置文件中进行以下配置:主要是在对应的路由中添加 add_header 这些东西既可

    server {
        listen       80;
        server_name localhost;
        location /demo/ {
            # 允许请求的域, *表示所有,一般生产上直接精确到允许访问的源地址
            add_header 'Access-Control-Allow-Origin' *;
            # 允许请求带上cookie
            add_header 'Access-Control-Allow-Credentials' 'true';
            # 允许请求的方法 比如get、post、head、delete、put等, *代表所有
            add_header 'Access-Control-Allow-Metheds' *;
            # 允许请求的header,一般根据你请求头里面的东西配置,*代表所有
            add_header 'Access-Control-Allow-Headers' *;


            proxy_pass  http://localhost:8080/;
        }
    }

Java服务配置CORS

这里采用的springboot版本为2.7.11

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;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class CORSConfig {

    @Bean
    public CorsFilter corsFilter(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        List<String> param = new ArrayList<String>();
        param.add("*");
        // 设置是否允许携带cookie,当这个值为true时,AllowedOrigins的值不能设置为*
//        corsConfiguration.setAllowCredentials(true);
        // 设置允许的源,生产环境不建议设置为*,一般具体到对应的地址
        corsConfiguration.setAllowedOrigins(param);
        // 设置可以额外添加的请求头
        corsConfiguration.setAllowedHeaders(param);
        // 设置允许的请求方法
        corsConfiguration.setAllowedMethods(param);

        // 设置所有路径都拦截
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);
        CorsFilter corsFilter = new CorsFilter(source);
        return corsFilter;
    }
}

注意:nginx,gateway,具体微服务;这三个上面如果有多个地方配置了CORS,导致响应头中会存在多个相同key,会导致浏览器不知道应该选用哪个。删除其他CORS配置,只保留一个地方配置就行。(前提是跨域请求才会报错,正常请求即使返回了这些内容,也不会报错,因为浏览器压根就不会进行CORS验证)

CORS具体逻辑

浏览器将跨域请求分为简单请求和非简单请求,区分方法为

1、请求方式为 HEAD、GET、POST

2、请求头中没有添加自定义的请求头,只存在Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(里面的值只能为application/x-www-form-urlencodedmultipart/form-datatext/plain

符合以上两个条件即为简单请求,不符合即为非简单请求

 CORS简单请求

浏览器判断跨域请求为简单请求的时候,会在请求头中添加Origin(表示源地址),服务器接收请求后,执行正常的接口处理逻辑,在响应的时候,如果允许跨域访问,一般即配置了CORS相关内容,那么会在响应头中添加一个Access-Control-Allow-Origin,表示请求允许的源地址,*表示允许所有地址,不允许跨域访问则没有这个响应头,浏览器拿到响应后,会判断响应头中是否存在Access-Control-Allow-Origin,如果存在,再判断值是否和当前源相同,否则报CORS相关跨域错误。

CORS非简单请求

浏览器判断当前请求为非简单跨域请求后,会以这个请求地址,发一个请求方式为options的请求(预检请求)

预检请求的请求头除了原有的内容,还添加了

Origin:源地址

Access-Control-Request-Method:之前请求的请求方式,不是本次预检请求的请求方式

Access-Conrol-Request-Headers:非简单请求多出的请求头字段

服务器收到请求后,检测这些字段后,确认允许此跨域请求后,就会给出回复

回复的响应头中包含

Access-Control-Allow-Origin:表示允许访问的源地址

Access-Control-Allow-Methods:表示允许访问的请求方法

Access-Control-Allow-Headers:表示允许额外添加的请求头

Access-Control-Allow-Creadentials:true,表示允许携带cookie

Access-Control-Allow-Max-Age:表示本次预检的有效期,有限期内,不会再发送预检请求

浏览器一旦通过了预检请求,在有效期内,浏览器进行此跨域访问,都会发简单请求,请求头中包含Origin,响应头中包含Access-Control-Allow-Origin

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值