【JAVA企业级开发】详解在前后端分离的项目开发过程中使用VUE-CLI脚手架搭建的前端项目产生的跨域问题和所有可能的解决方案

一什么是跨域,为什么会存在跨域?

1 首先我们要认识到究竟什么是跨域?

#协议跨域
http://a.baidu.com访问https://a.baidu.com;
#端口跨域
http://a.baidu.com:8080访问http://a.baidu.com:80;
#域名跨域
http://a.baidu.com访问http://b.baidu.com;

2 为什么在前后端分离的项目中有跨域问题的存在

①首先要认识清楚我们VUE项目大部分情况下是基于VUE-CLI脚手架构建的

vue-cli是vue框架开发的快速工程化命令工具。

②其次要认识清楚VUE-CLI是基于 webpack 构建的

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:
通过 @vue/cli 实现的交互式的项目脚手架。
通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。
一个运行时依赖 (@vue/cli-service),该依赖:
可升级;
***基于 webpack 构建***,并带有合理的默认配置;
可以通过项目内的配置文件进行配置;
可以通过插件进行扩展。
一个丰富的官方插件集合,集成了前端生态中最好的工具。
一套完全图形化的创建和管理 Vue.js 项目的用户界面。
Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。

vue-cli这个构建工具大大降低了webpack的使用难度,支持热更新,有webpack-dev-server的支持,相当于启动了一个请求服务器,给你搭建了一个测试环境,只关注开发就OK。

③清楚认知webpack组件中的webpack-dev-server本质上是小型Express服务器

webpack-dev-server是webpack官方提供的一个小型Express服务器。使用它可以为webpack打包生成的资源文件提供web服务。webpack-dev-server官方文档

webpack-dev-server 主要提供两个功能:

为静态文件提供服务
自动刷新和热替换(HMR)

3 浏览器的同源策略

同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

同源的定义
如果两个 URL 的 protocol、port (en-US) (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。

下表给出了与 URL http://store.company.com/dir/page.html 的源进行对比的示例:在这里插入图片描述

4 存在跨域的问题本质

由于开发时会用到webpack-dev-server,所以一定会产生跨域的问题
在这里插入图片描述

5 VUE-CLi解决跨域的实质出发点

此处介绍的使用devServer解决跨域,其使用原理就是http proxy将所有ajax请求发送给devServer服务器,在由decServer服务器做一次转发,发送给数据接口服务器由于ajax请求是发送给devServer服务器的,所以不存在跨域,而devServer由于是用node平台发送的http请求,自然也不设计到跨域问题,可以完美解决。(只有浏览器和服务器之间才会存在跨域问题)
在这里插入图片描述

6 Devserver http proxy的用法(不用在去配置nginx就可以解决跨域问题,爽歪歪):

基本用法:
mmodule.exports = {
  //...
  devServer: {
    proxy: {
      '/api': 'http://localhost:3000'
    }
  }
};

请求到 /api/xxx 现在会被代理到请求 http://localhost:3000/api/xxx, 例如 /api/user 现在会被代理到请求 http://localhost:3000/api/user
代理多个路径
module.exports = {
  //...
  devServer: {
    proxy: [{
      context: ['/auth', '/api'],
      target: 'http://localhost:3000',
    }]
  }
};

如果你想要代码多个路径代理到同一个target下, 你可以使用由一个或多个「具有 context 属性的对象」构成的数组:
忽略API前缀
module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        pathRewrite: {'^/api' : ''}
      }
    }
  }
};
请求到 /api/xxx 现在会被代理到请求 http://localhost:3000/xxx, 例如 /api/user 现在会被代理到请求 http://localhost:3000/user
忽略http安全提示
module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'https://other-server.example.com',
        secure: false
      }
    }
  }
};

默认情况下,不接受运行在 HTTPS 上,且使用了无效证书的后端服务器。如果你想要接受,只要设置 secure: false 就行。
跨域
module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
      }
    }
  }
};
上面的参数列表中有一个changeOrigin参数, 是一个布尔值, 设置为true, 本地就会虚拟一个服务器接收你的请求并代你发送该请求,

如果VUE项目中没有统一API前缀,在 proxy代理配置时就需要加上取消前缀配置,下面附上我完整的vue.config.js

const path = require('path')
const CompressionPlugin = require("compression-webpack-plugin")

function resolve(dir) {
  return path.join(__dirname, dir)
}

// vue.config.js
module.exports = {
  /*
    Vue-cli3:
    Crashed when using Webpack `import()` #2463
    https://github.com/vuejs/vue-cli/issues/2463
   */
  // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
  productionSourceMap: false,
  //打包app时放开该配置
  //publicPath:'./',
  configureWebpack: config => {
    //生产环境取消 console.log
    if (process.env.NODE_ENV === 'production') {
      config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
    }
  },
  chainWebpack: (config) => {
    config.resolve.alias
      .set('@$', resolve('src'))
      .set('@api', resolve('src/api'))
      .set('@assets', resolve('src/assets'))
      .set('@comp', resolve('src/components'))
      .set('@views', resolve('src/views'))

    //生产环境,开启js\css压缩
    if (process.env.NODE_ENV === 'production') {
        config.plugin('compressionPlugin').use(new CompressionPlugin({
          test: /\.(js|css|less)$/, // 匹配文件名
          threshold: 10240, // 对超过10k的数据压缩
          deleteOriginalAssets: false // 不删除源文件
        }))
    }

    // 配置 webpack 识别 markdown 为普通的文件
    config.module
      .rule('markdown')
      .test(/\.md$/)
      .use()
      .loader('file-loader')
      .end()

    // 编译vxe-table包里的es6代码,解决IE11兼容问题
    config.module
      .rule('vxe')
      .test(/\.js$/)
      .include
        .add(resolve('node_modules/vxe-table'))
        .add(resolve('node_modules/vxe-table-plugin-antd'))
        .end()
      .use()
      .loader('babel-loader')
      .end()

  },

  css: {
    loaderOptions: {
      less: {
        modifyVars: {
          /* less 变量覆盖,用于自定义 ant design 主题 */
          'primary-color': '#1890FF',
          'link-color': '#1890FF',
          'border-radius-base': '4px',
        },
        javascriptEnabled: true,
      }
    }
  },

  devServer: {
    port: 3000,
    proxy: {
     /* '/api': {
        target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro', //mock API接口系统
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '/jeecg-boot': ''  //默认所有请求都加了jeecg-boot前缀,需要去掉
        }
      },*/
      '/fbenergy': {
        target: 'http://192.168.1.36:8081', //请求本地 需要jeecg-boot后台项目
        ws: false, //无需代理 websocket
        changeOrigin: true, //解决跨域问题
        pathRewrite: {'/fbenergy': ''}  //所有请求中都没有统一api前缀,所以需配置忽略前缀
      },
    }
  },

  lintOnSave: undefined
}

二 解决跨域的另外三种方式

1 使用ajax的jsonp

前端代码
在这里插入图片描述
服务器后端代码
在这里插入图片描述
使用该方式的缺点:请求方式只能是get请求

2 使用jQuery的jsonp插件

插件下载网址:https://github.com/jaubourg/jquery-jsonp

前端代码
在这里插入图片描述后端服务代码

在这里插入图片描述
使用该方式的特点:与方式一相比,请求方式不只局限于get请求,还可以是post请求,但从服务器从获取的数据依然是jsonp格式

3 使用cors

前端代码
在这里插入图片描述
服务器代码
在这里插入图片描述
使用该方式的特点:与前两种方式相比,前端代码和未处理跨域前一样,即普通的ajax请求,但服务器代码添加了一段解决跨域的代码

// 设置:Access-Control-Allow-Origin头,处理Session问题
    response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    response.setHeader("Access-Control-Allow-Credentials", "true");
    response.setHeader("P3P", "CP=CAO PSA OUR");
    if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
        response.addHeader("Access-Control-Allow-Methods", "POST,GET,TRACE,OPTIONS");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type,Origin,Accept");
        response.addHeader("Access-Control-Max-Age", "120");
    }

cors高级使用:在springmvc中配置拦截器
创建跨域拦截器实现HandlerInterceptor接口,并实现其方法,在请求处理前设置头信息,并放行
在这里插入图片描述
在springmvc的配置文件中配置拦截器,注意拦截的是所有的文件
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牵牛刘先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值