欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【spring boot】https 前后端分离 跨域请求爬的坑

程序员文章站 2022-07-10 16:11:06
...

一·项目背景

 后端 基于 spring boot搭建,所有的请求做了 https ,开始并没有做前后端分离,因为前后端分离是大势所趋,

不管以后后端开发 是否 会替代 前端开发,前后端分离会越来越流行。

所以准备把项目做成前后端分离,没想到第一步就遇到了跨域请求的坑。如果你对照了网上所有跨域请求的例子都没有成功

可以参考我的,是否和你遇到的问题一致。

 前端 基于node js 搭建的 vue 项目。

二·示例

 开始认为处理跨域请求是很简单的事情,不就是在 消息头里 添加一个Access-Control-Allow-Origin

配置允许跨域请求的域名嘛。

后端实现 跨域请求其实就是相当简单的。

有两种方式

1·filter

 import org.springframework.stereotype.Component; 
import javax.servlet.*; 
import javax.servlet.http.HttpServletResponse; 
import java.io.IOException; 

@Component 
public class CorsFilter implements Filter { 
  final static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CorsFilter.class); 
  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-Max-Age", "3600"); 
    response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); 
    chain.doFilter(req, res); 
  } 
  public void init(FilterConfig filterConfig) {} 
  public void destroy() {} 
}
 2·spring boot 方式

/**
 * 说明:
 *
 * @author WangBin
 * @version v1.0
 * @date 2018/1/21/021.
 */
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*","http://www.baidu.com/")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600);
    }

}


Access-Control-Allow-Origin :允许跨域请求的 域名,底层接收 String 数组,传多个可以用 逗号分隔如

“http://www.baidu.com/”,"http://www.csdn.com/"

允许所有域名进行跨域访问 填写“*”,基于安全问题考虑,不建议填写 *

Access-Control-Allow-Methods:跨域请求 允许的 请求方式,允许所有填写 *

Access-Control-Max-Age:每次跨域请求前会发送一个OPTIONS请求,携带当前跨域请求的方法和域名,

去服务端检查,是否允许当前请求可以通过,如 当前请求的域名没有在Access-Control-Allow-Origin

里是不能继续发送真正的请求的。Access-Control-Max-Age 存的是当前校验的 有效时间 单位是秒

Access-Control-Allow-Headers:允许发送的内容类型,如

"Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"

三·坑

前端错误:XMLHttpRequest cannot load http://localhost:8080/user/login.

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

既然如此简单 那么坑在哪呢。坑在哪呢,坑其实都是自己埋下的。

1·先说前端的坑吧

前端使用的 axios ,我把 request 请求做了个封装代码大致如下:

/*Created by WangBin on 2017.12.06.
名称:全局请求 拦截器 处理
说明:*/
import axios from 'axios'
import {Message} from 'element-ui'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter);
// 创建axios实例
const service = axios.create({
    //请求地址前缀
    baseURL: 'https://172.18.12.36:8080/',
    timeout: 10000 // 请求超时时间
})

// request拦截器
service.interceptors.request.use(config => {
    //请求头部增加token信息
    // config.headers['LoginToken'] = '123';
    return config
}, error => {
    console.log(error)
    Promise.reject(error)
})

// respone拦截器
service.interceptors.response.use(
    response => {
        //未登录的跳转到登录页面
        if (response.data.status == 9500) {
            location.href="/#/login";
        } else {
            return response;
        }
    },
    error => {
        console.log('err' + error)
        Message({
            message: error.message,
            type: 'error',
            duration: 10 * 1000
        })
        return Promise.reject(error)
    })

export default service
这段代码的目的 是 把所有的 request 请求发送前都做一个拦截,并可以在拦截后可以做一些处理,如添加消息头,处理参数后发送请求给后端,不详细说了。

并编写了一个 util js

/*Created by WangBin on 2017.12.06.
名称:请求封装
说明:*/
import request from '../utils/request'
export function getLoginToken() {
    return localStorage.getItem("LoginToken");
    // return "456";
}
/*get请求*/
export function getRequest(url,data) {
    data["LoginToken"] = getLoginToken();
    return request({
        url: url,
        method: 'get',
        params: data
    })
}

/*delete请求*/
export function deleteRequest(url,data) {
    data["LoginToken"] = getLoginToken();
    return request({
        url: url,
        method: 'delete',
        params: data
    })
}

/*POST请求*/
export function postRequest(url,data) {
    data["LoginToken"] = getLoginToken();
    return request({
        url: url,
        method: 'post',
        params:data
    })
}

把不同的请求 做了个封装,现在看起来 好像每个请求都是一样的 只是 method 不同,然后 在每个参数data 的基础上 添加了 LoginToken


坑来了,首先尝试的是跨域请求登录方法,登录方法 是只允许 post 请求,所以调用 封装好的 axios 的 postRequest(url,data)

第一个参数 传 post 地址 URL 第二个传 要提交的参数 如:

                            var Form = {
                                userName:this.userName,passWord:this.passWord}
                            postRequest("user/login", Form).then((response) => {

看起来似乎没什么问题,最后发现 OPTIONS 请求发送到后端 ,前端竟然报错了,404【spring boot】https 前后端分离 跨域请求爬的坑

地址肯定没写错,也是post 提交。

问题 出在于,虽然 是post 请求,但是 提交的参数 是在URL 里拼接的。因为后端做了 请求拦截,

只有user/login 不会被拦截,其他的地址都会被重定向到 登录页面。所以导致了 404

根本原因是 使用axios post 方法不对,正确方式:

        var params = new URLSearchParams();
        params.append('userName', data.userName);
        params.append('passWord', data.passWord);
        postRequest("user/login",params).then((response) => {
          console.log(response)
        }, (response) => {
          console.log(response)
        }) .catch(function (response) {
          console.log(response)
        })

这样 便不会在 URL里拼接。

发送请求后前端竟然还报错:

XMLHttpRequest cannot load https://127.0.0.1:5211/user/login. Redirect from 'https://127.0.0.1:5211/user/login' to '

https://127.0.0.1:5211/login.html' has been blocked by CORS policy: Request requires preflight, which is disallowed

to follow cross-origin redirect.

是因为 跨域请求不允许 重定向,为什么会重定向呢,

2·后端的坑

因为 后端 在登录的时候 报错了

【spring boot】https 前后端分离 跨域请求爬的坑
解决后端错误后请求成功 ok 啦。

你是不是高兴的太早了,一个深坑 马上来了。

请求成功是 在 360 浏览器上 操作的。那么 继续做前端开发,换用 火狐浏览器,

前端 报错 errError: Network Error

经过一番测试 发现 控制台 有如下错误 ,原因是 证书 和 本地 测试域名 不匹配 导致浏览器没有信任,360浏览器貌似是没有做 这些校验

【spring boot】https 前后端分离 跨域请求爬的坑

访问 我们要请求的地址:

Your connection is not secure


The owner of 127.0.0.1 has configured their website improperly. To protect your information from being stolen,
Firefox Developer Edition has not connected to this website.
Learn more…


Report errors like this to help Mozilla identify and block malicious sites


添加信任即可。

【spring boot】https 前后端分离 跨域请求爬的坑