天天看点

前后端分离项目经典跨域访问问题:四种常用方法。解决Allow-Origin header is present on the requested resource1.什么是跨域?2.同源策略3.项目场景*4.解决方法(重点)

目录导航

  • 1.什么是跨域?
  • 2.同源策略
  • 3.项目场景
  • *4.解决方法(重点)
    • (1)使用@CrossOrigin注解
    • (2)使用corsfilter过滤器
    • (3)全局跨域设置。(推荐)
        • 继承WebMvcConfigurer,通过addCorsMappings方法实现跨域访问。
    • **(4)nginx反向代理(代理转发)重要

1.什么是跨域?

(1)简单的来说,跨域就是浏览器内核同源策略对JavaScript代码的一种限制。例如在当前服务器的网站下不可执行另外网站的js代码。

(2)常见的例如:dom和js对象无法获取,ajax请求服务器数据显示:No ‘Access-Control-Allow-Origin’ header is present on the requested resource.错误。

2.同源策略

(1)同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。

(2)浏览器判断同源的标准:

首先分析一下一个url的组成:http://localhost:8080/xxx.html

协议:http https 都是常见的协议

ip:一般本机的ip都是127.0.0.1或localhost来代替。

端口:比如常见的网站端口默认是80,等等。

http://localhost/bbb.html 与 http://localhost/aaa.html 同源 协议 ip 端口都一致

http://localhost/bbb.html 与 https://localhost/aaa.html 跨域 协议不一致

http://localhost/bbb.html 与 http://127.0.0.1/aaa.html 跨域 ip 不一致(浏览器认为localhost和127.0.0.1是属于跨域,很多人会混淆)

http://localhost/xxx.html 与 http://localhost:8080/xxx.html 端口不一致 属于跨域

3.项目场景

(1)前端项目发布服务端口为80,后端服务端口为8081的情况下。这时候前端ajax请求后端服务就属于跨域访问,返回的数据将会被浏览器拦截,从而报错。(Allow-Origin’ header is present on the requested resource)

*4.解决方法(重点)

(1)使用@CrossOrigin注解

前后端分离项目经典跨域访问问题:四种常用方法。解决Allow-Origin header is present on the requested resource1.什么是跨域?2.同源策略3.项目场景*4.解决方法(重点)
前后端分离项目经典跨域访问问题:四种常用方法。解决Allow-Origin header is present on the requested resource1.什么是跨域?2.同源策略3.项目场景*4.解决方法(重点)

(2)使用corsfilter过滤器

前后端分离项目经典跨域访问问题:四种常用方法。解决Allow-Origin header is present on the requested resource1.什么是跨域?2.同源策略3.项目场景*4.解决方法(重点)

整理好的代码片段如下:

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() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        //是否允许请求带有验证信息
        corsConfiguration.setAllowCredentials(true);
		corsConfiguration.addAllowedOriginPattern("http://localhost:8081");  //单个域名设置
        /*允许服务端访问的客户端请求头*/
        corsConfiguration.addAllowedHeader("*");
        /*允许访问的方法名,GET POST等*/
        corsConfiguration.addAllowedMethod("*");
        //注册url路径,/**为全部路径匹配
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}
           

(3)全局跨域设置。(推荐)

继承WebMvcConfigurer,通过addCorsMappings方法实现跨域访问。

代码如下:

import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) { 
    	// 注册路径                             //注册所有域名
        registry.addMapping("/**").allowedOriginPatterns("*")
        		//注册可以请求的方法
                .allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
                .allowCredentials(true).maxAge(3600);
    }
}
           

**(4)nginx反向代理(代理转发)重要

先上配置,如下:配置文件在安装好的nginx路径下的conf文件夹中的nginx.conf文件

events {
		worker_connections  1024;
	}
http{
	
	server {
			   listen 8081;
			   server_name 192.168.1.100;

			   location / {
			   		proxy_set_header Host $http_host;
					proxy_set_header X-Real-IP $remote_addr;
					proxy_set_header REMOTE-HOST $remote_addr;
					proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
					proxy_pass http://192.168.1.100:8082;
			   if ($request_method = 'OPTIONS') {
						add_header Access-Control-Allow-Origin $http_origin;	
						add_header Access-Control-Allow-Credentials true;
						add_header Access-Control-Allow-Methods $http_access_control_request_method;
						add_header Access-Control-Allow-Headers $http_access_control_request_headers;
						add_header Access-Control-Max-Age 1728000;
						add_header Content-Length 300;
						return 204;
					}
				}
			}	
}
           
  1. 首先,配置文件一定要有events{}和http{server{}}。
  2. 其次,server{}中的listen则是代表我们监听的服务端口。(这里是监听192.168.1.100:8081的服务,然后转发到8082端口)。
  3. server_name则是服务器的ip或域名。
  4. 最最最重要的就是location的配置,’/'代表匹配所有192.168.1.100:8081发出的请求。例如:http:192.168.1.100:8081/xx/xxx.js就会被/匹配。
  5. proxy_set_header:设置转发后的请求头的相关信息
  6. X-Real-IP :设置真实请求的ip
  7. REMOTE-HOST:设置真实的请求的真实主机地址
  8. X-Forwarded-For:第一个ip为客户端请求的ip,第二个则是代理ip(客户端:http://localhost:8081,代理:http://localhost:8082)
  9. proxy_pass:代理转发url。就是由nginx发送http://localhost:8082,这样nginx和后台就处于同源下,这样就实现跨域访问了。
  10. 注意: 当proxy_pass的url后面跟上/斜杆时,转发的url有以下情况

    假设现在用http://localhost:8081/aaa/xxx.html去访问。

    ① 当location /aaa/ {

    proxy_pass http://localhost:8082

    } 代理url:http://localhost:8082/aaa/xxx.html

    ② 当location /aaa/ {

    proxy_pass http://localhost:8082/

    } 代理url:http://localhost:8082/xxx.html

    由①、②对比,可以知道,当转发的url后面有斜杆时,就会将匹配http://localhost:8081/aaa/变成http://localhost:8082/,如果没有,则只替换前面的协议+ip+端口。

    ③ 当location /aaa/ {

    proxy_pass http://localhost:8082/bbb/

    } 代理url:http://localhost:8082/bbb/xxx.html

    ④ 当location /aaa/ {

    proxy_pass http://localhost:8082/bbb

    } 代理url:http://localhost:8082/bbbxxx.html

    由③、④对比,相同的是,都改变了url,不同的是,有斜杆的③分多了一级,而④是直接拼接。

  11. add_header:添加响应头信息。(跨域访问,并不是请求不到数据,而是接收不到数据)。所以,我们可以在响应头中添加对应origin值,add_header Access-Control-Allow-Origin $http_origin; 这样浏览器就不会拦截。其他数据类似corsfilter配置的信息,允许cookies、请求方法类型之类的,可自行上网查找。
  12. $request_method = ‘OPTIONS’:浏览器将cors请求(跨域请求)分为两种。一是简单请求。二是非简单请求。只要同时满足以下两大条件,就属于简单请求。

    (1) 请求方法是以下三种方法之一:HEAD、GET、POST

    (2)HTTP的头信息不超出以下几种字段:Accept、Accept-Language、ContentLanguage、Last-Event-ID

    (3)Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

    凡是不同时满足上面两个条件,就属于非简单请求。

    简单请求浏览器会自动添加一些附加的头信息,而非简单请求浏览器会多出一次附加的请求(options)。options请求会在正式请求前发送,该请求测试接口是否通过,通过才会发送正式请求。你需要确认后台不会拦截该请求,否则你的正式请求将无法被发送。

跨域访问记录。

继续阅读