赞
踩
一·项目背景
后端 基于 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
- })
- }
第一个参数 传 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·后端的坑
因为 后端 在登录的时候 报错了
你是不是高兴的太早了,一个深坑 马上来了。
请求成功是 在 360 浏览器上 操作的。那么 继续做前端开发,换用 火狐浏览器,
前端 报错 errError: Network Error
经过一番测试 发现 控制台 有如下错误 ,原因是 证书 和 本地 测试域名 不匹配 导致浏览器没有信任,360浏览器貌似是没有做 这些校验
访问 我们要请求的地址:
添加信任即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。