对于开发者而言,客户端与服务端通讯时出现跨域问题是常见的事,跨域的典型特征就是一次点击两次请求,一次 options 预检请求,通过后再发一次实际的get 或 post 请求,这是因为客户端向服务端请求数据时发送的是复杂请求,所以要解决跨域问题,只需要将复杂请求变更为简单请求即可,这里多提一嘴复杂请求和简单请求的概念:
1、请求类型为GET、POST、HEAD三种;
2、请求头类型为Accept、Accept-Language、Content-Type、Content-Language四种;
3、Content-Type的值为text/plain、multipart/form-data、application/x-www-form-urlencoded三种。
满足以上三条的请求即为简单请求,反之则为复杂请求。但是在实际项目开发中,第一条是容易满足的,一个项目使用 get 或者 post 请求类型基本就够用了;第二条较难满足,由于部分业务的需要可能会使用到各种业务头、自定义请求头等;第三条也很难满足,大部分项目都会使用 application/json 作为 Content-Type值。综上说明将复杂请求转变为简单请求是很难完成的。因此本文就解决跨域问题提供第二种方式:使用代理,配置好代理,不论是简单请求还是复杂请求都不会有options 的出现。
打开前端 vue 工程,找到 vue.config.js 文件并打开,添加如下代码:
module.exports = {
devServer: {
port: 9000,
proxy: {
'/webapi/test': {
target: 'http://12.5.78.222:8888, //目标服务器地址
changeOrigin: true, //是否跨域
secure: false, //是否https接口
pathRewrite: { //路径重写
'^/webapi/test': '/webapi'
}
}
}
}
}
说明:上述配置的意思是:凡是路径以 /webapi/test 开头的请求都会将其本地服务器地址转向目标服务器地址(12.5.78.222:8888),另外由于对路径进行了重写,所以路径 /webapi/test 就变成了 /webapi,最终实现了
http://localhost:9000/webapi/test ==> http://12.5.78.222:8888/webapi
当我们使用 postman 测试时,请求 url 输入 http://12.5.78.222:8888/webapi 是可以正常访问的;当我们在浏览器地址栏中输入http://localhost:9000/webapi/test 同样可以正常访问,原因就是添加了上述代码使得客户端做了代理。还有一点需要注意,如果要配置多个代理,是可以在 proxy中添加多个的,但有顺序要求:
module.exports= {
devServer: {
port: 9000,
proxy: {
'/webapi/test1': {
target: 'http://12.5.78.222:8888, //目标服务器地址
changeOrigin: true, //是否跨域
secure: false, //是否https接口
pathRewrite: { //路径重写
'^/webapi/test1': '/webapi/one'
}
},
'/webapi/test2': {
target: 'http://12.5.78.222:8888, //目标服务器地址
changeOrigin: true, //是否跨域
secure: false, //是否https接口
pathRewrite: { //路径重写
'^/webapi/test': '/webapi/two'
}
},
'/webapi': {
target: 'http://12.5.78.222:8888, //目标服务器地址
changeOrigin: true, //是否跨域
secure: false, //是否https接口
pathRewrite: { //路径重写
'^/webapi': '/webapi'
}
}
}
}
}
上述配置的顺序是正确的,/webapi 因为涵盖了 /webapi/test1和/webapi/test2,所以如果 /webapi 放在最前面那么 /webapi/test1 和 /webapi/test2 就永远不会匹配到,拿个 if-else 举个例子就容易明白了:
if(path.startsWith('/webapi')) {
function1(){}
}else if(path.startsWith('/webapi/test1')) {
function2(){}
}else if(path.startsWith('/webapi/test2')) {
function3(){}
}
startWith 是字符串开头匹配方法,如果 path 是以 /webapi 开头,不管 /webapi 后面接的是什么内容,都会进第一个 if 而不会进 else if。