本文将会介绍小编在工作中遇到的跨域场景及解决办法。
场景一:开发过程中前后端联调跨域
解决办法:
-
使用webpack解决跨域
-
使用nginx解决跨域
-
使用cors解决跨域
场景二:前后端分开部署跨域
解决办法:
-
使用nginx解决跨域
-
使用cors解决跨域
解决办法
首先我们先准备一个简单的项目用于演示。
项目准备步骤:
-
新建文件夹 cross-domain。
-
进入 cross-domain 文件夹下,新建 web 文件夹(用于存放前端代码)、新建 server 文件夹(用于存放后端代码)。
-
准备前端项目。
进入 web 文件夹下,新建 index.html 文件,新建 index.js 文件。
index.html 内容如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>跨域演示</title>
</head>
<body>
跨域演示
<button id="btn">点我发起ajax请求</button>
<h1 id="main"></h1>
<script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>
<script src="./index.js"></script>
</body>
</html>
index.js 内容如下:
$(function() {
$('#btn').on('click', function() {
$.ajax({
// url: 'http://localhost:9527/getData', // 如果直接访问接口就会产生跨域,报错 (Access to XMLHttpRequest at 'http://localhost:9527/getData' from origin 'http://0.0.0.0:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.)
url: '/api/getData', // '/api' 跨代理的标识,在 webpack.config.js 中配置
success: function(res) {
$('#main').text(res.data)
}
});
});
});
- 准备后端项目。
进入 server 文件夹下,新建 app.js 文件。
app.js内容如下:
const express = require('express')
const app = express()
const port = 9527
// 接口地址为 http://localhost:9527/getData
app.get('/getData', (req, res) => {
let tmpData = {
code: 200,
msg: '成功',
data: '这是后台返回的数据!'
}
res.send(tmpData)
})
const server = app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
在 server 文件夹下打开命令行。
-
执行命令
yarn init -y初始化项目(不想用 yarn 的同学可以用 npm 或 cnpm ) -
执行命令
yarn add express@4.17.1安装 express -
执行命令
node app.js启动后端服务
得到一个get方式的接口http://localhost:9527/getData
如果直接在 http://0.0.0.0:8080/ 服务下请求 http://localhost:9527/getData 接口就会产生跨域请求不成功。什么是跨域
项目目录结构为:
├── cross-domain
├── web
├── index.html
└── index.js
└── server
└── app.js
使用webpack解决跨域
使用webpack解决跨域适用于开发过程中前后端联调跨域。
在 web 文件夹下打开命令行。
-
执行命令
yarn init -y初始化项目(不想用 yarn 的同学可以用 npm 或 cnpm ) -
执行命令
yarn add webpack@3.10.0 webpack-dev-server@2.9.7 -D
打开 package.json 文件,在 devDependencies 前加入如下代码:
"scripts": {
"serve": "webpack-dev-server"
},
进入 web 文件夹下,新建 webpack.config.js 文件。
webpack.config.js 内容如下:
module.exports = {
entry: './index.js',
devServer: {
port: 8080,
host: '0.0.0.0',
open: true,
inline: true,
hot: true,
disableHostCheck: true,
proxy: {
'/api': {
target: 'http://localhost:9527', //服务地址
ws: false,
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}
}
在命令行中执行命令yarn serve 启动开发服务,会看浏览器打开地址为 http://0.0.0.0:8080/ 的页面,点击按钮发送请求,会看到 http://localhost:8080/api/getData 的接口请求成功,通过代理后它其实获取的是 http://localhost:9527/getData 接口的数据。
提示:用 webpack 开发环境处理了跨域,打包后要部署到生产环境的代码只是静态文件,是没有解决跨域的,有些同学会以为在开发环境用 webpack 处理了跨域,生产环境也就处理好了。
使用nginx解决跨域
- 安装 nginx
安装好 nginx 后,修改 conf 文件夹下的 nginx.conf 文件内容为:
user root owner;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8080;
server_name localhost;
location / {
# root 为前端代码根路径
# root D:/cross-domain/web; #windows环境,若不生效的情况下,可将web文件夹移动到nginx下的html文件夹下,并修改路径为相对路径(root html/web)
root /Users/its-wild/cross-domain/web; #mac环境
index index.html index.htm;
}
#后台服务配置,配置了这个location便可以通过http://域名/xxxx 访问
location ^~ /api/ {
# proxy_pass http://localhost:9527; #端口后没有带/,实际访问地址为 http://localhost:9527/api/getData
proxy_pass http://localhost:9527/; #端口后带/,实际访问地址为 http://localhost:9527/getData
proxy_redirect off;
proxy_set_header Host 127.0.0.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
allow all;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
include servers/*;
}
此处展示的是mac环境下的nginx.conf文件。
启动nginx后,http://localhost:8080/ 点击按钮发送请求,会看到 http://localhost:8080/api/getData 的接口请求成功,通过代理后它其实获取的是 http://localhost:9527/getData 接口的数据。
提示:前端开发完成后打包的都是一些静态文件,在服务器上用nginx部署和开发环境用nginx启服务开发是一样的。
使用cors解决跨域
cors(Cross-Origin Resource Sharing)跨域资源共享,应该算是现在最为推荐的跨域处理方案。不仅适用于各种Method,而且更加方便和简单。当然只有现代浏览器支持。
这个东西只需要后台做处理就可以,前端直接访问接口全路径,如果需要特别处理可以参照cors详细介绍文档。
此处我们修改 app.js 内容如下:
const express = require('express')
const app = express()
const port = 9527
//设置跨域访问
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
})
// 接口地址为 http://localhost:9527/getData
app.get('/getData', (req, res) => {
let tmpData = {
code: 200,
msg: '成功',
data: '这是后台返回的数据!'
}
res.send(tmpData)
})
const server = app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
修改 index.js 内容如下:
$(function() {
$('#btn').on('click', function() {
$.ajax({
url: 'http://localhost:9527/getData',
// url: '/api/getData', // '/api' 跨代理的标识,在 webpack.config.js 中配置
success: function(res) {
$('#main').text(res.data)
}
});
});
});
重新启动后端服务,再通过 http-server 启动一个前端服务(在 web 文件夹下打开命令行,执行 http-server -p 8080 -o ), 在http://127.0.0.1:8080/页面点击按钮发起请求,会在 network 看到的请求地址为http://localhost:9527/getData 的请求返回成功。
提示:127.0.0.1、0.0.0.0、localhost、本机ip(如:10.0.123.57)都指向的是同一个地址