阅读 261

前端常见跨域问题及解决办法

本文将会介绍小编在工作中遇到的跨域场景及解决办法。

场景一:开发过程中前后端联调跨域

解决办法:

  1. 使用webpack解决跨域

  2. 使用nginx解决跨域

  3. 使用cors解决跨域

场景二:前后端分开部署跨域

解决办法:

  1. 使用nginx解决跨域

  2. 使用cors解决跨域

解决办法

首先我们先准备一个简单的项目用于演示。

项目准备步骤:

  1. 新建文件夹 cross-domain。

  2. 进入 cross-domain 文件夹下,新建 web 文件夹(用于存放前端代码)、新建 server 文件夹(用于存放后端代码)。

  3. 准备前端项目。

进入 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)
            }
        });
    });
});
复制代码
  1. 准备后端项目。

进入 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解决跨域

  1. 安装 nginx

mac环境安装教程

windows环境安装教程

安装好 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详细介绍

这个东西只需要后台做处理就可以,前端直接访问接口全路径,如果需要特别处理可以参照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)都指向的是同一个地址

文章分类
前端
文章标签