• 详解跨域处理


    非同源策略(跨域)请求的处理方案

    1. 聊聊你对跨域的理解

    前端开发进化史

    • 服务器渲染 「半服务器渲染 SSR」

    • 客户端渲染

    为啥会产生跨域

    • 服务器分离:WEB服务器、数据服务器、图片服务器…

    • 云信息共享:第三方API接口

    • 有助于分离开发:开发跨域、部署同源

    • ……

    解决方案

    • JSONP

    • CORS

    • Proxy

    • ……

     同源策略请求 && 非同源策略(跨域)请求

       HTML页面预览的地址:http://127.0.0.1:5500/index.html

       基于Ajax发送请求的数据接口地址:http://127.0.0.1:9999/user/list

       如果两个地址的“协议、域名、端口号”完全一致,则是同源请求,只要有一个不一样,则就是跨域请求!!

          + 同源请求:把web页面和后台的接口程序部署在“相同服务器的相同服务下”

          + 跨域请求:页面和后台分开部署「同一台服务器的不同端口下、或者不同服务器下...」

       项目场景:

          + 开发的时候:我们在自己的电脑上启动服务预览项目,但是后台的程序在其他的服务器上,没有在一起,此时的数据请求就是“跨域”的!!

          + 部署到服务器:

            + 全部署在一起(相同服务器的相同服务下),此时就是同源「不建议」

            + 当代部署一般都是分服务器部署,也就是页面和后台是部署在不同服务器上的,此时就是跨域

          + ...

       默认情况下不允许Ajax跨域请求,因为浏览器有“安全策略”

          Access to XMLHttpRequest at 'https://www.jianshu.com/asimov...' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

       服务器和服务器之间默认是没有跨域限制的

     ==============================

     非同源策略(跨域)请求方案:

       + proxy跨域代理:原理就是利用“服务器和服务器之间不存在跨域”来实现的

         步骤:

           @1 在本地启动一个服务:一方面可以实现页面的预览,另一方面也可以代理转发数据请求

           @2 我们以后再发数据请求,发送给本地启动的这个服务,而这个服务会去真正的服务器上获取到相关的数据,再返回给客户端!!

         + 本地开发的时候,我们基于proxy跨域代理来完成「webpack-dev-server、Node...」

         + 部署到服务器的时候,我们一般是基于nginx的反向代理来处理

       + CORS跨域资源共享:默认因为浏览器的安全策略,是不允许ajax跨域访问的,但是如果服务器设置了 Access-Control-Allow-Origin 响应头信息,设置允许这个源发送请求,那么浏览器也就不在去限制了!!

         步骤:

           @1 由服务器设置允许源

             Access-Control-Allow-Origin 设置允许的源「白名单机制」

             Access-Control-Allow-Credentials 是否允许携带资源凭证「例如:cookie」

               服务器端设置了允许,则客户端也要配合设置允许

               axios.defaults.withCredentials = true;

               xhr.withCredentials=true;

             Access-Control-Allow-Headers 设置允许的请求头

             Access-Control-Allow-Methods 设置允许的请求方式

           @2 在CORS跨域共享中,客户端首先会尝试发送一个OPTIONS试探请求,验证是否连接成功,连接成功后,再发送真正的请求!!

       + JSONP跨域解决方案

         原理:利用了

  • <script src="http://127.0.0.1:1001/user/list?callback=func">script>
  •  服务器端:

    1. /*-CREATE SERVER-*/
    2. const express = require('express'),
    3. app = express();
    4. app.listen(1001, () => console.log(`服务启动成功,正在监听1001端口!`));
    5. app.get('/user/list', (req, res) => {
    6. // 获取传递进来的callback值,例如:'func'
    7. let { callback } = req.query;
    8. // 准备数据
    9. let result = {
    10. code: 0,
    11. data: ['张三', '李四']
    12. };
    13. // 返回给客户端指定的格式,例如:’函数名(数据)‘
    14. res.send(`${callback}(${JSON.stringify(result)})`);
    15. });
    16. /* STATIC WEB */
    17. app.use(express.static('./'));

    proxy 

    1. /*-CREATE SERVER-*/
    2. const express = require('express'),
    3. request = require('request'),
    4. app = express();
    5. app.listen(1001, () => console.log(`服务启动成功,正在监听1001端口!`));
    6. // 服务器接收到客户端发送过来的请求
    7. app.get('/aaa', (req, res) => {
    8. // 向简书发送相同请求,从简书服务器获取想要的数据「不存在域的限制的」
    9. let jianURL = `https://www.jianshu.com/asimov/subscriptions/recommended_collections`;
    10. req.pipe(request(jianURL)).pipe(res);
    11. });
    12. /* STATIC WEB */
    13. app.use(express.static('./'));

    CORS

    1. /*-CREATE SERVER-*/
    2. const express = require('express'),
    3. app = express();
    4. app.listen(1001, () => console.log(`服务启动成功,正在监听1001端口!`));
    5. /*-MIDDLE WARE-*/
    6. // 设置白名单
    7. let safeList = ["http://127.0.0.1:5500", "http://127.0.0.1:3000", "http://127.0.0.1:8080", "http://127.0.0.1:5501"];
    8. app.use((req, res, next) => {
    9. let origin = req.headers.origin || req.headers.referer || "";
    10. origin = origin.replace(/\/$/g, '');
    11. origin = !safeList.includes(origin) ? '' : origin;
    12. res.header("Access-Control-Allow-Origin", origin);
    13. res.header("Access-Control-Allow-Credentials", true);
    14. res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With");
    15. res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,HEAD");
    16. req.method === 'OPTIONS' ? res.send('OK') : next();
    17. });
    18. /*-API-*/
    19. app.get('/list', (_, res) => {
    20. res.send({
    21. code: 0,
    22. message: 'zhufeng'
    23. });
    24. });
    25. /* STATIC WEB */
    26. app.use(express.static('./'));

    vue.config.js

    webpack-dev-server

    1. const ENV = process.env.NODE_ENV;
    2. module.exports = {
    3. lintOnSave: ENV !== 'production',
    4. publicPath: './',
    5. productionSourceMap: false,
    6. // 对webpack-dev-server的配置
    7. devServer: {
    8. // 配置跨域代理「可以配置对多台服务器的代理」
    9. proxy: {
    10. // 所有以“/api”开始的请求,都发送到代理服务器「走这个配置」
    11. "/api": {
    12. target: "https://www.jianshu.com/asimov",
    13. ws: true,
    14. changeOrigin: true,
    15. pathRewrite: {
    16. "^/api": ""
    17. }
    18. },
    19. // 所有以“/zhihu”开始的请求,都代理到知乎服务器
    20. "/zhihu": {
    21. target: "https://news-at.zhihu.com/api/4",
    22. ws: true,
    23. changeOrigin: true,
    24. pathRewrite: {
    25. "^/zhihu": ""
    26. }
    27. }
    28. }
    29. }
    30. };

    部署到服务器上:基于nginx实现反向代理

    处理原理

    自己基于node实现

     
    

    const request = require('request');

    app.get('/subscriptions/recommended_collections', function (req, res) {

    let url = 'https://www.jianshu.com/asimov' + req.url;

    req.pipe(request(url)).pipe(res);

    });


    扩展:其他跨域方案「配合iframe」

    • postMessage

    • window.name

    • document.domin

    • location.hash

    • ……

    ----------------------------------------

  • 相关阅读:
    dvwa-暴力破解(low-high)
    通过Xshell7连接云服务Linux系统级上传文件
    【JS】JavaScript入门笔记第五弹之预解析、对象~
    【踩坑】.NET异步方法不标记async,Task<int> 返回值 return default问题
    【编程题】【Scratch四级】2021.12 森林运动会
    C 语言的整数类型
    DockerFile发布Java微服务并部署到Docker容器
    Blob和ArrayBuffer和File
    【git merge/rebase】详解合并代码、解决冲突
    Spring的事务管理机制
  • 原文地址:https://blog.csdn.net/weixin_60968779/article/details/125957945