跨域原理以及跨域解决方案

写在前面的话

在火热的互联网IT时代,越来越多的前端开发工程师和H5开发工程师都会遭遇到人(猿)生中一个名词:跨域,尤其是新手第一次接触这个东西时,顿感手足无措。本篇文章将会对跨域从基本概念到详细应用进行一一解读,废话不多,直接走起....

跨域到底是什么?

先上张图,给各位压压惊...

跨域错误提示信息

是不是又看到了熟悉的 No 'Access-Control-Allow-Origin' (这是跨域的经典标志), 惊不惊喜,意不意外,是不是很熟悉!

认识URL网址

URL地址: http://www.justbecoder.com:80/article/index.html
    http                                  超文本传输协议
    www.justbecoder.com                   域名
    80                                    端口号
    article/index.html                    文件目录与文件名      

同源策略

概念

同源策略是浏览器最核心也是最基本的的安全功能,是指我们在发送网络请求时请求必须要遵守同源策略,即域名、协议、端口号都要相同

意义

是为了保证用户信息的安全,防止恶意的网站窃取数据。

触发跨域的场景以及原因

当同源策略中的 域名、协议、端口号有一样不相同时,都会触发跨域

假定当前在的网址是: http://www.justbecoder.com:80/,当我向以下网址发送请求时都会触发跨域
    url: https://www.justbecoder.com:80/   // 协议不同 --- 喂,老婆,我听不懂呀,你说话加密啦!
    url: http://www.baidu.com:80/          // 域名不同 --- 哎呀,菇凉认错认了,你不是我老婆
    url: http://www.justbecoder.com:8080/  // 端口不同 --- 是你老婆没错,但是你没有找对你老婆身上的门啊

我们必须是用跨域吗?

现在网站的功能越来越多,网站中的图片、视频、数据库有可能都不在同一台服务器上,不同协议、不同域名、不同端口号的服务器进行相互请求和响应是必然的,所以跨域一定是会使用到的!

如何应用和解决跨域

问题场景:

// 客户端  跨域请求 --- 所在位置 http://localhost:80/index.js
$.ajax({
    // 端口号不同,引发跨域
    url: 'http://localhost:3000/user/info',
    type: 'get',
    data: {
        id: 110
    },
    success: function(msg) {
        console.log(msg)
    },
    error: function(err) {
        console.log(err)
    }
})  

// 服务器端响应 --- 以Node.js为例,服务器位置http://localhost:3000
var express = require('express');
var router = express.Router();

router.get('/user/info', function(req, res) {
    // 获取请求的参数
    // req.query.id // 当然这个参数目前是没有用滴...
    // ... 查询数据库中对应的用户info,假定当前获取的数据为
    var userInfo = {
        id: 110,
        username: '天王盖地虎',
        userimg: '/uploads/user/23456.jpg'
    };
    // 响应给客户端
    res.send(200, userInfo);
})

问题信息:

当请求按照上面的代码进行发送和响应时,会触发跨域错误,因为二者的端口号是不一致的,没有遵循同源策略

JSONP跨域请求解决方案:

这里是重点,重点(敲黑板...),在使用script标签引入js文件时是不受同源策略影响的,so我们就可以拿这个做文章了

// 当我们向某个位置发送请求时,请求和响应要做出如下改变
客户端请求:
    <script src="http://localhost:3000/user/info?id=110" type="text/javascript"></script>
服务器端响应:
    var userInfo = {
        id: 110,
        username: '天王盖地虎',
        userimg: '/uploads/user/23456.jpg'
    };
    
    // 序列化 -- 格式 {"id":110,"username":"天王盖地虎","userimg":"/uploads/user/23456.jpg"}
    var userInfoJsonStr = JSON. stringify(userInfo);
    
    // 格式 -- 'getInfo({"id":110,"username":"天王盖地虎","userimg":"/uploads/user/23456.jpg"})'
    res.send(200, 'getInfo('+userInfoJsonStr+')'); 

客户端接收数据
    // 响应到的数据(浏览器 Network自行查看),该格式下的字符串,相当于在调用一个名字为 getInfo 的函数,传递的参数为 {"id":110,"username":"天王盖地虎","userimg":"/uploads/user/23456.jpg"}
    // getInfo({"id":110,"username":"天王盖地虎","userimg":"/uploads/user/23456.jpg"})
    
    在客户端的JS脚本中,定义对应的函数 getInfo()
    <script type="text/javascript">
        function getInfo(msg) {
            // 此处的msg就是获取响应的userInfo
            // 接下来你想干啥就干啥
        }
    </script>

以上的这个过程,我们就解决了跨域的问题。

JSONP跨域请求原理

  1. 创建script标签,将原有的url地址、参数数据设置为src的地址,并附加参数(包括约定的callback函数名)

     var script = document.createElement('script');
     script.src = 'http://localhost:3000/user/info?callback=getInfo&id=110';
     document.body.appendChild(script);
    
  2. 服务器端响应数据时,要将响应的数据设置为指定的格式 接收的函数名(JSON字符串格式数据)

     // 获取客户端约定的回调函数名
     var callback = req.query.callback;
     var userInfo = JSON.stringify({
         id: 110,
         username: '天王盖地虎',
         userimg: '/uploads/user/23456.jpg'
     });
     res.send(200, callback + '(' + userInfo + ')');
    
  3. 在客户端定义对应的函数名的函数,该函数的形参就是接收到的服务器端响应数据

     <script>
         function getInfo(msg) {
             // msg 服务器端的响应数据
             console.log(msg)
         }
     </script>
    

jQuery封装的JSONP请求

$.ajax({
    // 请求的url地址
    url: 'http://localhost:3000/user/info',
    // 发送数据方式
    type: 'get',
    // 参数
    data: {
        id: 110
    },
    // 请求成功时的callback
    success: function(msg) {
        // 你想干啥就干啥
    },
    // 预期服务器返回的数据类型
    dataType: 'jsonp',
    // 指定定义回调函数名的参数名,若不指定默认参数名为callback
    jsonp: 'callback',
    // 指定回调函数名,若不指定默认为系统自动生成
    // jsonpCallback: 'getInfo'
})

结语

以上是我整理的关于跨域的原理以及相应的JSONP跨域解决方案,希望能够给各位小伙伴在工作和学习中提供一定的帮助。 欢迎小伙伴积极留言探讨,不要忘记收藏和点赞喜欢呦,还可以进行打赏,请哥喝杯咖啡呀。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 一、浏览器的同源策略 1.什么是同源? 所谓“同源”指的是”三个相同“。相同的域名、端口和协议,这三个相同的话就视...
    徐国军_plus阅读 834评论 1 3
  • JavaScript是一种在Web开发中经常使用的前端动态脚本技术。在JavaScript中,有一个很重要的...
    西瓜w阅读 1,748评论 0 1
  • 同源策略 理解跨域首先必须要了解同源策略。同源策略是浏览器上为安全性考虑实施的非常重要的安全策略。何谓同源:URL...
    48892085f47c阅读 716评论 0 6
  • 本节内容:实现跨域常用的两种方式 —— JSONP 和 CORS 零:跨域报错展示 在非同源情况下,调用 Ajax...
    NathanYangcn阅读 3,235评论 2 12
  • 前言 在 上一篇文章 中介绍了很多关于镜像的指令, 本文就介绍下如何使用 Dockerfile 来构建镜像。 用法...
    anyesu阅读 2,962评论 0 3