前后端分离项目,解决跨域请求问题

目录

 

浏览器的同源策略

同源策略的限制

什么是跨域问题

跨域请求解决方案

代理模式(proxy)

CORS(本项目采用的方案)

复杂跨域请求引起的预检问题

SpringSecurity配置对OPTIONS请求并没有放开登录认证


浏览器的同源策略

浏览器出于网站安全性的考虑,限制不同源之间的资源相互访问的一种政策。只有当协议+域名+端口这三个部分完全相同的才认为是同源。

同源策略的限制

值得一提的是,有些请求是不受到跨域限制。例如:WebSocket,script、img、iframe、video、audio标签的src属性等。

  • AJAX 请求不能发送。

  • 无法获取DOM元素并进行操作。

  • 无法读取Cookie、LocalStorage 和 IndexDB

什么是跨域问题

当一个资源去访问另一个不同域名或者同域名不同端口的资源时,就会发出跨域请求。如果此时另一个资源不允许其进行跨域资源访问,那么访问的那个资源就会遇到跨域问题。或者是两个资源的传输协议不一致(如一个是http,一个是https)时,也会出现跨域问题。

 

跨域请求解决方案

代理模式(proxy)

  • 将请求转发给后端进行处理(有点像重定向)

 

 

const express = require('express');
const router = express.Router();
const request = require('request');
router.get('*', (req, res, next) => {
    let path = req.path.replace(/^\/proxy/, '');
    request.get(`http://127.0.0.1:3000${path}`, (err, response) => {
        res.json(JSON.parse(response.body));
    });
});
module.exports = router;

这样,我们在前端访问/proxy/info/normal后,就会自动转发到http://127.0.0.1:3000/proxy/info/normal

 

前端ajax部分如下:

 

 

 
document.getElementById('btn-1').addEventListener('click', function() {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
            alert(xhr.responseText);
        }
    }
    xhr.open('get', '/proxy/info/normal');
    xhr.send(null);
});

该方法的优点很明显:不需要第三方服务http://127.0.0.1:3000/info/normal进行任何改造。

当然,该方法也有一些缺点:

  • 首先,需要你有一个自己的后端服务能够接收并转发请求。如果你进行本地的纯静态页面开发,则需要一些浏览器插件或自动化工具中集成的本地服务器来实现。

  • 此外,如果请求包含一些特殊的请求头(例如cookie等等),需要在转发时特殊处理。

 

CORS(本项目采用的方案)

同源策略往往过于严格了,为了解决浏览器的这个问题,w3c提出了CORS(Cross-Origin Resource Sharing)标准。CORS通过相应的请求头与响应头来实现跨域资源访问。

如果我们打开控制台,可以在请求头中发现一个叫origin的头信息,它表明了请求的来源。这是浏览器自动添加的。

 

 

 
Referer: http://127.0.0.1:8085/
Origin: http://127.0.0.1:8085   <============   origin
Accept: */*
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8
Pragma: no-cache

与之对应的,服务器端的响应头中一个头信息为Access-Control-Allow-Origin,表明接受的跨域请求来源。显而易见,这两个信息如果一致,则这个请求就会被接受。

 

 

 
router.get('/cors', (req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8085');
    res.json(data);
});

如果将Access-Control-Allow-Origin的值设置为*,则会接受所有域的请求。这时的客户端不需要任何配置即可进行跨域访问。

然而,还有一个问题,CORS默认是不会发送cookie,但是如果我希望这次的请求也能够带上对方服务所需的cookie怎么办?那就需要再进行一定的改造。

Access-Control-Allow-Origin相配套的,还有一个叫Access-Control-Allow-Credentials的响应头,如果设置为true则表明服务器允许该请求内包含cookie信息

 

 

 
router.get('/cors', (req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8085');
    res.setHeader('Access-Control-Allow-Credentials', true);
    res.json(data);
});

以上前端参数的设置,我们可以在后端设置一个跨域的过滤器配置来实现,配置文件如下

添加GlobalCorsConfig配置文件来允许跨域访问。

 

 

 
package com.macro.mall.config;
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;
/**
 * 全局跨域配置
 * Created by macro on 2019/7/27.
 */
@Configuration
public class GlobalCorsConfig {
    /**
     * 允许跨域调用的过滤器
     */
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        //允许所有域名进行跨域调用
        config.addAllowedOrigin("*");
        //允许跨越发送cookie
        config.setAllowCredentials(true);
        //放行全部原始头信息
        config.addAllowedHeader("*");
        //允许所有请求方法跨域调用
        config.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

缺点是:

  • 需要对跨域的服务接口进行一定的改造。如果该服务因为某些原因无法改造,则无法实现。但这种改造还是相对较小的。

  • 不兼容一些“古董”浏览器。

复杂跨域请求引起的预检问题

参考文章ajax跨域简单请求与复杂请求

 

SpringSecurity配置对OPTIONS请求并没有放开登录认证

由于复杂的跨越请求需要先进行一次OPTIONS请求进行预检,我们的应用整合了SpringSecurity,对OPTIONS请求并没有放开登录认证。因此我们要修改Security的配置文件,允许Security放开options请求

在SecurityConfig类的configure(HttpSecurity httpSecurity)方法中添加如下代码。

 

 

 
.antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
.permitAll()

img

git项目地址:https://gitee.com/peng_2ni/kkb-parent

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值