通常情况下,跨域问题是由服务端依靠CORS或JSONP等方法解决。为了在开发过程中不依靠后端解决跨域问题,可以使用一台与前端页面服务的Host相同的代理服务器,将请求发送给这台代理服务器,然后再由代理服务器将请求转发给真实的服务器。

使用服务代理可绕开浏览器同源策略的限制。服务代理可以使用Nginx等应用创建,当然Vue CLI也支持创建代理。

Vue CLI代理需要在vue.config.js中进行配置。

注:Vue CLI代理仅是在开发过程中使用的。


简单代理

Vue CLI创建代理最简单的方式就是:

module.exports = {
  devServer: {
    proxy: 'http://localhost:4000'
  }
}

配置完成后,重启前端页面服务,然后将原本请求的Host改为与页面服务相同的Host即可。例如本地页面服务为http://localhost:8080,要发送的Ajax请求为http://localhost:4000/api/user。那么将Ajax请求改为http://localhost:8080/api/user即可通过服务代理绕过浏览器的同源策略。

由于页面的端口与服务代理的端口一致,所以在发送请求时,可以将http://localhost:8080/api/user直接简写为/api/user

这种配置方式的服务代理,首先会根据请求路径,在项目的public目录下寻找对应的资源:

  • 如果public目录中有请求所对应的资源,那么服务器就直接将该资源发送给浏览器;
  • 如果public目录中没有请求所对应的资源,那么服务器就会将这次请求通过代理的方式完整地转发给proxy配置的服务器。

例如http://localhost:8080/api/user

  • 如果public目录中有api目录,并且api目录下一个名为user这个资源,那么服务器就直接将user这个资源发送给浏览器。
  • 如果public目录中没有api目录或者有api目录但是api目录下没有名为user的资源,那么服务器就会认为该请求需要走代理。

也就是说,当请求了前端不存在的资源时,请求就会被转发给被代理的服务器(优先匹配前端资源)。

这种配置方式的优缺点如下:

  • 优点:配置简单。
  • 缺点:不能配置多个代理,不能灵活控制某些请求是否走代理。

完整配置

module.exports = {
  devServer: {
    proxy: {
      '/api': {             // 访问代理时的路径前缀
        target: '<url>',    // 代理的目标路径
        ws: true,           // 是否支持 webSocket
        changeOrigin: true, // 是否将请求头中的Host改成与target一样的Host(默认为true)
      },
      '/foo': {
        target: '<other_url>'
      },
    }
  },
}

例如:

module.exports = {
  devServer: {
    proxy: {
      '/api': {                           // 路径前缀
        target: 'http://localhost:5000',  // 代理目标
        ws: true,
      },
    }
  },
}

那么在使用代理请求http://localhost:5000的资源时,除了使用当前服务的Host外,还需要加上路径前缀/api。即通过http://localhost:8080/apihttp://localhost:5000的资源进行访问。

在使用http://localhost:8080/api访问时,代理会将整个访问路径(包括前缀)原封不动地转发给http://localhost:5000这个服务器。例如请求http://localhost:8080/api/user那么http://localhost:5000会接收到/api/user这个请求。

如果在转发时要将路径前缀去掉(例如请求http://localhost:8080/api/userhttp://localhost:5000接收到的是/user请求),可以配置路径转发规则pathRewrite

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:5000',
        pathRewrite: {  // 路径转发规则
          // key:用于匹配路径的正则匹配表达式
          // value:是替换路径中匹配的内容
          '^/api': '',
        },
        ws: true,
        changeOrigin: true,
      },
    }
  },
}

在微服务架构中,一个服务使用一台(或多台)服务器运行,那么可以根据服务来精简配置项。例如:

module.exports = {
  devServer: {
    proxy: {
      '/users': {  // http://localhost:5000/users
        target: 'http://localhost:5000',
      },
      '/orders': {  // http://localhost:5001/orders
        target: 'http://localhost:5001',
      },
    }
  },
}

使用完整配置时的优缺点如下:

  • 优点:可以配置多个代理,可以灵活地控制请求是否使用代理。
  • 缺点:配置略繁琐,请求资源时必须使用路径前缀。