1. 程式人生 > >【spring boot】https 前後端分離 跨域請求爬的坑

【spring boot】https 前後端分離 跨域請求爬的坑

一·專案背景

 後端 基於 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

地址肯定沒寫錯,也是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·後端的坑

因為 後端 在登入的時候 報錯了

解決後端錯誤後請求成功 ok 啦。

你是不是高興的太早了,一個深坑 馬上來了。

請求成功是 在 360 瀏覽器上 操作的。那麼 繼續做前端開發,換用 火狐瀏覽器,

前端 報錯 errError: Network Error

經過一番測試 發現 控制檯 有如下錯誤 ,原因是 證書 和 本地 測試域名 不匹配 導致瀏覽器沒有信任,360瀏覽器貌似是沒有做 這些校驗


訪問 我們要請求的地址:

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

新增信任即可。