Web前端跨域(Access-Control-Allow-Origin)

什么是跨域?

https://www.guobao0730.com/babel/

       一个URL地址由 协议(https://) +  域名(www.guobao0730.com)  +  端口号(443)   +  资源地址(babel) 组成,当协议、域名、端口号中任意一个发生改变的时候,就会被当做是不同的源,这时候就会触发跨域的问题。

        浏览器的安全策略规定当前域名的js不允许访问其它域的地址,核心原因是XMLHttpRequest 不支持跨域请求。 

怎么解决跨域的问题?

           跨域的错误提示:

大致意思是表示XMLHttpRequest这个对象不支持跨域的请求

既然不支持,那么就找一个支持的对象,比如img、audio、video、link标签,它们的特点如下:

                     1、上述标签都支持跨域请求,

                     2、通过GET请求的方式可以将数据传递出去,

                     3、无法接受到服务器返回的数据。

通过script标签来实现跨域的请求,该标签的特点如下:

                        1、支持跨域请求

                        2、通过GET请求的方式可以将数据传递出去

                        3、 当服务器返回一个js表达式(var data = { “state”:200,”msg”:”请求成功”,”data”:”用户不存在” })时,可以正常获取服务器返回的数据,该种方式就相当于通过script标签引入一个外部的js文件一样,当通过load事件监听到外部js文件加载完毕以后,使用外部js文件中的data对象即可获取数据。

开发环境

 Vue 2 和 Vue 3解决跨域的问题可以参见:https://blog.csdn.net/yuanlaijike/article/details/80522621 

注意:

     在dev开发模式下使用的webpack的proxy可以解决跨域的问题,但是这种方式在生产环境下不能使用,在生产环境中需要使用nginx 进行反向代理。其实原理都一样,都是通过搭建一个中转服务器转发请求进行规避跨域的问题。

生产环境

方式一:

通过nginx 反向代理来解决生产环境下网络请求

        如果当前是生产模式,那么前端通过proxy(代理)解决跨域的同时,在nginx中需要进行反向代理,具体需要在nginx.conf文件中进行如下配置:

server {
  listen       9527;
  server_name  localhost;
  client_max_body_size 20M;
  #charset koi8-r;

  #access_log  logs/host.access.log  main;

  root /usr/local/nginx/html/dsep/dist;
  index index.html index.html;

  #  prod-api 是代理的名称
  location /prod-api/ {
    proxy_redirect off;
  proxy_pass http://172.16.1.19:8080/;
    }


  #error_page  404              /404.html;

  # redirect server error pages to the static page /50x.html
  #
    error_page   500 502 503 504  /50x.html;
  location = /50x.html {
  root   html;
}

  # proxy the PHP scripts to Apache listening on 127.0.0.1:80
  #
  #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
      #}
  
  # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
  #
  #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}
  
  # deny access to .htaccess files, if Apache's document root
  # concurs with nginx's one
  #
  #location ~ /\.ht {
  #    deny  all;
  #}
}

其中 prod-api 表示代理的名称,http://172.16.1.19:8080/ 是代理路径的真实地址。

例如:代理路径为:/prod-api  ,真实的服务器地址为:http://172.16.1.19:8080 ,如下代码

# just a flag
ENV = 'production'

# base api
VUE_APP_BASE_API = '/prod-api'

# 发布环境下的服务器请求地址
VUE_APP_BASE_URL = 'http://172.16.1.19:8080'

那么反向代理需如下配置,这里注意需要将 /prid-api  改为 prod-api ,真实地址后面添加 / 

    # prod-api 是代理的名称
    location /prod-api/ {
        proxy_redirect off;
        proxy_pass http://172.16.1.19:8080/;
    }

方式二:

根据开发环境的不同设置前端是否需要进行代理,如下代码:

request.js (axios二次封装文件)

const service = axios.create({
baseURL: process.env.NODE_ENV === 'development' ? process.env.VUE_APP_BASE_API : process.env.VUE_APP_BASE_URL, // 开发环境进行代理,否则不需要
withCredentials: true,
timeout: 50000
})

vue.config.js文件

const developmentProxy = {
  [process.env.VUE_APP_BASE_API]: {
    target: process.env.VUE_APP_BASE_URL,
    changeOrigin: true,
    pathRewrite: {
      ['^' + process.env.VUE_APP_BASE_API]: ''
    }
  }
}

// 开发环境下请求数据时需要代理,正式环境不需要
const proxy = process.env.NODE_ENV === 'development' ? developmentProxy : {}

module.exports = {
  publicPath: './',
  outputDir: 'dist',
  assetsDir: 'static',
  lintOnSave: process.env.NODE_ENV === 'development',
  productionSourceMap: false,
  devServer: {
    port: port,
    open: true,
    overlay: {
      warnings: false,
      errors: true
    },
    proxy: proxy
  },
  configureWebpack: {
    name: name,
    resolve: {
      alias: {
        '@': resolve('src')
      }
    }
  },
  chainWebpack(config) {
    config.plugins.delete('preload') // TODO: need test
    config.plugins.delete('prefetch') // TODO: need test



    // set preserveWhitespace
    config.module
      .rule('vue')
      .use('vue-loader')
      .loader('vue-loader')
      .tap(options => {
        options.compilerOptions.preserveWhitespace = true
        return options
      })
      .end()

    config
      // https://webpack.js.org/configuration/devtool/#development
      .when(process.env.NODE_ENV === 'development',
        config => config.devtool('cheap-source-map')
      )

    config
      .when(process.env.NODE_ENV !== 'development',
        config => {
          config
            .plugin('ScriptExtHtmlWebpackPlugin')
            .after('html')
            .use('script-ext-html-webpack-plugin', [{
            // `runtime` must same as runtimeChunk name. default is `runtime`
              inline: /runtime\..*\.js$/
            }])
            .end()
          config
            .optimization.splitChunks({
              chunks: 'all',
              cacheGroups: {
                libs: {
                  name: 'chunk-libs',
                  test: /[\\/]node_modules[\\/]/,
                  priority: 10,
                  chunks: 'initial' // only package third parties that are initially dependent
                },
                elementUI: {
                  name: 'chunk-elementUI', // split elementUI into a single package
                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
                },
                commons: {
                  name: 'chunk-commons',
                  test: resolve('src/components'), // can customize your rules
                  minChunks: 3, //  minimum common number
                  priority: 5,
                  reuseExistingChunk: true
                }
              }
            })
          config.optimization.runtimeChunk('single')
        }
      )
  }
}

.env.development文件如下:

NODE_ENV='development'
# must start with VUE_APP_
VUE_APP_ENV = 'development'

VUE_APP_BASE_API = '/dev-api'

#base url http://kykjbyg.lxygm.com/ http://wfbyg.hbkykj.cn
VUE_APP_BASE_URL = 'http://wfbyg.hbkykj.cn'

#appid
VUE_APP_WECHAT_APPID='wxcee7b521765291ad'
VUE_CLI_BABEL_TRANSPILE_MODULES = true

.env.production 文件如下:

NODE_ENV='production'
# must start with VUE_APP_
VUE_APP_ENV = 'production'

VUE_APP_BASE_API = '/prod-api'

#base url
VUE_APP_BASE_URL = 'http://wfbyg.hbkykj.cn'
#appid
VUE_APP_WECHAT_APPID='wxcee7b521765291ad'

如果觉得文章有帮助到你,可以扫描以下二维码
   请本文作者 喝一杯
pay_weixin pay_weixin

发表评论

电子邮件地址不会被公开。 必填项已用*标注