前端跨域主流解决方案(Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy)

问题背景

前后端分开开发,由于浏览器本身的同源策略(服务端没有这个限制),导致了前端去访问服务端接口时会产生跨域。
经典报错:Access to XMLHttpRequest at ‘http…’ from origin ‘null‘ has been blocked by CORS policy
image.png

解决方案:

说明:目前网上的解决方案有9-10种,包括了:1.cors 2.node正向代理 3.nginx反向代理 4.JSONP 5.websoket 6.window.postMessage 7.document.domain + iframe 8.window.location.hash + ifame 9.window.name + ifame 10.浏览器开启跨域(终极方案) 参考:https://juejin.cn/post/6844904126246027278#heading-33

这里我就不写这么多了,毕竟很多基本上也用不到,就写目前公司主流的两种跨域解决方案

  1. 客户端:cors 服务端:cors
  2. 客户端:proxy 服务端:nginx

方式一:cors跨域

cors跨域主要是后台配置,只要后台实现了cors跨域,那么浏览器去请求接口就不会有跨域了。
以后台node为例,配置cors跨域:

const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors());

缺点:1.对后台要求高,需要后台懂cors跨域,且需要知道怎么配置安全性才高(配的不好就容易遭受攻击)。
优点:前端无需进行任何配置,后台配置一次,开发和线上环境都可以使用该接口

方式二:客户端:proxy 服务端:nginx

如果你的后台不愿意帮你配置cors,或者不太懂怎么配置,那么靠我们自己也是很快能解决的。
开发阶段:proxy
proxy解决跨域其实就是使用node正向代理。代表:vue和react框架
原理为:当我们使用vue或者react开发项目时,会使用npm run serve/npm start来启动项目,此时就是我们本机开启了一个服务端(与浏览器同源),而服务端和服务端发送请求是不跨域的,跨域只存在浏览器中。此时浏览器的消息发送路线如图
image.png
proxy常用配置:

module.exports = {
    
    
    // cli3 代理是从指定的target后面开始匹配的,不是任意位置;配置pathRewrite可以做替换
    devServer: {
    
    
      proxy: {
    
    
        '/yourapi': {
    
       //代理api,/yourapi的意义在于,声明axios中url已/api开头的请求都适用于该规则,注意是以/yourapi开头,即:axios.post({url: '/yourapi/xxx/xxx'})
          target: 'yourserver',   //服务器真实api地址,即需要请求的目标接口,此处target的意义在于:造成跨域是因为访问的host与我们的请求头里的origin不一致,所以我们要设置成一致,这个具体请看下文
          pathRewrite: {
    
     
               '^/yourapi': 'https://我是服务器/api'   //重写路径
        // 此处是大部分文章都不会明说的的地方,
        // 既然我们设置了代理,则所有请求url都已写成/yourapi/xxx/xxx,那请求如何知道我们到底请求的是哪个服务器的数据呢
        // 因此这里的意义在于, 以 /yourapi开头的url请求,代理都会知道实际上应该请求那里,
        // ‘我是服务器/yourapi’,后面的/api根据实际请求地址决定,即我的请求url:/yourapi/test/test,被代理后请求的则是
        // https://我是服务器/yourapi/test/test
          } 
        }
      }
    }
  }

线上阶段:nginx
由于proxy只用于开发阶段,所以线上阶段一般是使用nginx来进行反向代理,其中的原理图如下:
image.png
跟正向代理的原理图很像是吧,这里我们需要了解一下正向代理和反向代理的区别:
1、位置不同
正向代理,架设在客户机和目标主机之间;(我们npm run serve就是在客户机架设的)
反向代理,架设在服务器端;(nginx是放在服务器上的)
2、代理对象不同
正向代理,代理客户端,服务端不知道实际发起请求的客户端
反向代理,代理服务端,客户端不知道实际提供服务的服务端
3、用途不同
正向代理,为在防火墙内的局域网客户端提供访问Internet的途径;
反向代理,将防火墙后面的服务器提供给Internet访问;
4、安全性不同
正向代理允许客户端通过它访问任意网站并且隐藏客户端自身,因此必须采取安全措施以确保仅为授权的客户端提供服务;反向代理都对外都是透明的,访问者并不知道自己访问的是哪一个代理。
正向代理是客户端找代理,把自己的请求转发给服务端;而反向代理,则是服务端找代理,把自己接受到的请求转发给背后的其他机器。正向代理,代理服务器为客户端服务;反向代理,代理服务器为服务端服务。

nginx常用配置:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log debug;
pid        /var/run/nginx.pid;

events {
    
    
    worker_connections  1024;
}

http {
    
    
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  60s;


    client_max_body_size 1024m;

    #gzip  on;
    gzip on;
    gzip_min_length  1k;
    gzip_buffers     4 16k;
    gzip_http_version 1.1;
    gzip_comp_level 2;
    gzip_types     text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
    gzip_vary on;
    gzip_proxied   expired no-cache no-store private auth;
    gzip_disable   "MSIE [1-6]\.";

    server {
    
    
        listen       80;
        server_name  127.0.0.1 stdemo.suntang.com;

	      #添加头部信息
        proxy_set_header Cookie $http_cookie;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;

        location / {
    
    
            #vue项目部署路径
            root /usr/share/nginx/html/;
            #解决页面刷新404问题
            try_files $uri $uri/ /index.html last;
            index  index.html index.htm;
            add_header Cache-Control "no-cache, no-store";
        }

        location /image/ {
    
    
            root   /var/filecenter/;
        }
        location /static/ {
    
    
            root   /var/filecenter/;
        }
        location /car/ {
    
    
            root   /var/filecenter/;
        }

        #接口端
        location /police/ {
    
    
            proxy_pass   http://127.0.0.1:8080/police/;
            proxy_redirect default;
            proxy_http_version 1.1;
            proxy_connect_timeout   60;
            proxy_send_timeout      60;
            proxy_read_timeout      90;
        }

        #地图api
        location /geoserver/ {
    
    
            proxy_pass   http://192.168.1.182:8060/geoserver/;
            proxy_redirect default;
        }

        # redirect server error pages to the static page /50x.html
        #
        # 系统临时维护请打开下面这行注释,并重启nginx,维护完毕后请注释下年这行,并重启nginx
        rewrite ^(.*)$ /maintainace.html break;

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
    
    
            root   /usr/share/nginx/html/;
        }
    }
#    include /etc/nginx/conf.d/*.conf;
}

这里nginx的配置这块还是蛮多的,这里就不过多的解释了。需要了解的可以看看这篇文章:https://juejin.cn/post/7007346707767754765。看着内容很多,但是其实主要就修改几个地方就可以了。下次我再写文章详细的讲一下nginx配置。

猜你喜欢

转载自blog.csdn.net/weixin_43239880/article/details/129980147