zoukankan      html  css  js  c++  java
  • axios解决跨域问题

    最近把我自己的网站升级生成前后端分离的项目(vue+springBoot),不可避免的就遇到了跨域问题。从中学到了许多知识,随便分享出来,也巩固下所学。

         谈到跨域,首先得了解CORS(Cross origin resource sharing) 跨域资源共享,它是w3c的一个标准,是一份浏览器技术规范,提供了web服务从不同网域传来沙盒脚本的方法,以避免浏览器的同源策略,是比JSONP模式的高级版。JSONP只支持GET请求方式,而CORS除了GET请求方式以外也支持其他的HTTP请求。CORS允许浏览器发送跨域服务器,发出XMLHttpRequest请求,从而克服AJAX只能同源请求。(想要了解为什么有跨域问题的产生,请了解浏览器的同源策略)

        浏览器发出CORS请求,需要对请求头增加一些信息,服务器会根据这些信息来是否决定同意这次请求。需要的头信息字段如下:

        (1)Access-Control-Allow-Origin

                  这个头信息字段是必须的。它指定允许进入来源的域名、ip+端口号 。 如果值是 ‘*’ ,表示接受任意的域名请求,这个方式不推荐,主要是因为其不安全,而且因为如果浏览器的请求携带了cookie信息,会发生下图错误:

        (2) Access-Control-Allow-Credentials

                    该字段是可选的。它设置是否可以允许发送cookie,true表示cookie包含在请求中,false则相反,默认为false。如果项目需要cookie就得设置该字段了。CORS请求默认不发送Cookie和HTTP认证信息的,所以在此基础上同时也需要在前端设置(以axios为例): axios.defaults.withCredentials = true

        (3)Access-Control-Max-Age

                    该字段是可选的。用于配置CORS缓存时间,即本次请求的有效期,单位为秒。

        (4)Access-Control-Allow-Methods

                  该字段可选。设置允许的请求方法。

         (5)Access-Control-Allow-Headers

                 该字段可选。设置允许的请求头信息

          (...)其他请参考相关资料

           提示:这些设置在后端的拦截器中设置。
     

         对于axios,它是vue2提倡使用的轻量版的ajax。它是基于promise的HTTP库。它会从浏览器中创建XMLHttpRequests。如果对axios不太了解,可以先看下这个两个博客:https://www.kancloud.cn/yunye/axios/234845    和   https://www.jianshu.com/p/7a9fbcbb1114

         了解到这些之后就可以解决跨域问题啦, 详细代码如下:

        (1) vue.js

          

    import axios from 'axios'
    import store from '../store'
    import { getToken } from '@/utils/auth'
    import { Message, MessageBox } from 'element-ui'
    // 每次请求携带cookies信息
    axios.defaults.withCredentials = true
    // 创建axios实例
    const service = axios.create({
    baseURL: process.env.BASE_API, // api的base_url
    timeout: 15000 // 请求超时时间
    })
    // request拦截器
    service.interceptors.request.use(config => {
    console.log(store.getters.token)
    if (store.getters.token) {
    console.log(getToken())
    config.headers['X-Token'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
    var token = getToken()
    Object.assign(config.headers, { 'token': token })
    }
    return config
    }, error => {
    // Do something with request error
    console.log(error) // for debug
    Promise.reject(error)
    })
    // respone拦截器
    service.interceptors.response.use(
    response => {
    /**
    * code为非20000是抛错 可结合自己业务进行修改
    */
    console.log(response.data)
    const res = response.data
    if (res.code !== 20000) {
    Message({
    message: res.message,
    type: 'error',
    duration: 5 * 1000
    })

    // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
    if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
    MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
    confirmButtonText: '重新登录',
    cancelButtonText: '取消',
    type: 'warning'
    }).then(() => {
    store.dispatch('FedLogOut').then(() => {
    location.reload() // 为了重新实例化vue-router对象 避免bug
    })
    })
    }
    return null
    } else {
    return response.data
    }
    },
    error => {
    if (error.message === 'Network Error' && error.config.url.endsWith('/license')) {
    Message({
    message: '无法连接到本地代理程序,请确认代理程序是否运行正常!',
    type: 'error',
    duration: 5 * 1000
    })
    } else {
    console.log(error + ' ' + error.config.url) // for debug
    Message({
    message: error.message + ' ' + error.config.url,
    type: 'error',
    duration: 5 * 1000
    })
    }
    return Promise.reject(error)
    }
    )
    export default service
     (2)springBoot

      

    package xin.toheart.door.filter;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.Set;

    @WebFilter(urlPatterns = { "/*" }, filterName = "loginAuthFilter")
    public class LoginAuthFilter implements Filter {
    private static Logger logger = LoggerFactory.getLogger(LoginAuthFilter.class);


    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse rep = (HttpServletResponse) response;
    // 设置允许多个域名请求
    String[] allowDomains = {"http://www.toheart.xin","http://192.168.10.213:8080","http://localhost:8080"};
    Set allowOrigins = new HashSet(Arrays.asList(allowDomains));
    String originHeads = req.getHeader("Origin");
    if(allowOrigins.contains(originHeads)){
    //设置允许跨域的配置
    // 这里填写你允许进行跨域的主机ip(正式上线时可以动态配置具体允许的域名和IP)
    rep.setHeader("Access-Control-Allow-Origin", originHeads);
    }


    // 设置服务器允许浏览器发送请求都携带cookie
    rep.setHeader("Access-Control-Allow-Credentials","true");
    // 允许的访问方法
    rep.setHeader("Access-Control-Allow-Methods","POST, GET, PUT, OPTIONS, DELETE, PATCH");
    // Access-Control-Max-Age 用于 CORS 相关配置的缓存
    rep.setHeader("Access-Control-Max-Age", "3600");
    rep.setHeader("Access-Control-Allow-Headers","token,Origin, X-Requested-With, Content-Type, Accept,mid,X-Token");
    response.setCharacterEncoding("UTF-8");
    // response.setContentType("application/json; charset=utf-8");
    chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }


    }

  • 相关阅读:
    [JavaScript] 根据字符串宽度截取字符串
    [JavaScript] 时间戳格式化为yyyy-MM-dd日期
    [JavaScript] 获取昨日前天的日期
    [As3.0] 获取本机信息
    [CSS3] 几种分割线实现方法
    [JS] js 判断用户是否在浏览当前页面
    [JS] 理解jquery的$.extend()、$.fn和$.fn.extend()
    [JS] 屏蔽右键
    [JS] jq绑定事件的参数传递
    [CSS3] 各种角度的三角形绘制
  • 原文地址:https://www.cnblogs.com/zhangycun/p/10944071.html
Copyright © 2011-2022 走看看