CORS & JSONP 学习笔记一

什么是跨域?

首先,现代浏览器为了安全,做了一个同源限制.

也就是所谓的同源安全策略.

本质上,其实是不存在所谓的跨不跨域的.
把浏览器想象成一个发送网络请求的软件.
按照道理来说,请求都是可以发送出去的.
但是在 web 端,浏览器里,这么做的就不合适.
如果网络上的接口可以不受限制的被任意人调用.
那将是一个非常混乱的场景.
所以,为了防止这种情况,浏览器做了这个同源策略来防止这种情况发生.
对,一般服务器不管这个事情.

跨域指的是,A网站内部向B网站发送一个AJAX请求.

由于浏览器有同源策略的限制,默认情况下,是不允许 A网站向 B 网站请求数据资源的.

http://my.website.com/ ---> http://your.website.com/ 是不允许的.

具体来说,凡是发送请求中,协议,主机名,端口号 有一个不同,即为跨域请求.

上述例子:my.website.comyour.website.com 就属于主机名不同而导致的跨域.

具体可以参照下面这个表.

image.png

总结一句:

协议相同 + 域名相同 + 端口号相同

浏览器才认为是同一个网站.
才不同受到同源策略的影响.
才可以正常的发送 AJAX 请求.

其他情况下,发送 AJAX 请求,都属于跨域.

请注意: 这里说的是 XMLHttpRequest 下的 AJAX 请求.

对于 <img> , <script>, <link> 等标签,就不存在跨域请求.(除非对方后台做了防盗链)

继续补充:

所谓的同源策略是浏览器实现的,而和后台服务器无关.
A 发送请求到 B. 请求实际上是发送到了 B 后台, B后台接受到数据后.
其实也有返回.
只不过,这个数据返回到浏览器之后,浏览器把这个数据给劫持了.不让A网站使用.


为什么要跨域?

既然跨域这么麻烦,都不能从网站后台拿到数据,那为什么还要搞跨域呢?

因为当一个项目变大时,把所有的内容都丢在一个网站或者是后台服务器中是不现实的.

比如:

一个网站体量很大.有很多可以独立且复杂的业务

  • 比如有一个订单管理的后台数据API网站服务.
  • 比如有一个用户管理的后台数据API网站服务.
  • 比如有一个新闻管理的后台数据API网站服务.

最后剩下的就是web的UI层面的东西.

把这个UI层面的东西和哪个数据服务API的网站集成在一起比较合适呢?

都不适合.

它应该是一个专门的网站.

image.png

所以域名可能存在如下情况:

  • 主网站(UIWeb)域名为: http://www.relax.com/
  • 订单数据服务接口域名为: https://order.relax.com/orderList
  • 用户数据服务接口域名为: https://users.relax.com/userList
  • 新闻数据服务就扣域名为: http://news.relax.com/newList

所以,UIWeb 如果需要请求这数据.

  • 请求订单数据: 协议不同 https|http , 二级域名不同 order | www , 端口号不同 443|80 --> 跨域
  • 请求用户数据: 协议不同 https|http , 二级域名不同 users | www , 端口号不同 443|80 --> 跨域
  • 请求新闻数据列表: 协议相同 http|http , 二级域名不同 order | www , 端口号相同 80|80 --> 跨域

不管请求哪个后台服务器的数据,都存在跨域的情况.

也就是无法利用 ajax 异步的获取到数据内容.


利用 jsonp 进行跨域

jsonp 跨域是里用在浏览器中,下载一个script标签是不受同源策略限制的特性.(bootcdn中不是有很多的js文件下载吗?)

具体实现原理大概分下面几步

  • 客户端动态的创建一个 script 标签
  • 设置 script 标签的src 为跨域的服务器后台.
  • src 中需要带一个 callback 查询字符串,告诉后台,前端提供的方法名是什么.
  • 然后后端,直接返回一一串 callback(data) 的字符串给浏览器即可.

前端端口是:8080

button.addEventListener('click', function () {
    // 利用下载script标签是不存在浏览器同源策略的特点.
    const scriptTag = document.createElement('script')
    scriptTag.type = 'text/javascript'
    // 第一 22222 端口号不同.
    // 第二 callback=show 是传递给22222后台服务器的查询字符串参数.
    // 第三 后台服务器根据拿到了这个callback = show,往前端输出一些文本流.(这里就是和利用下载script标签一模一样.)
    scriptTag.src = 'http://localhost:12345/getUserinfo?callback=show'
    document.body.appendChild(scriptTag)
  },false)

  // 这里的show 方式就是上述 jsonp 中的 callback 查询字符串指定的值.
  function show (user) {
    let dataStr = ""
    for(let prop in user) {
      dataStr += prop  + ":" + user[prop] + "<br>"
    }
    unOriginPlaceHolder.innerHTML = dataStr
  }

后端端口是:12345

const app = require('express')()
const url = require('url')
const queryString = require('querystring')

app.get('/getUserInfo', (request, response) => { 
  const queryObj = url.parse(request.url, true).query
  const callback = queryObj.callback // 获取callback参数

  const data = {
    userid: 1,
    name: '李四',
    age: 22,
    profession: '软件工程师'
  }

  const objStingIfy = JSON.stringify(data)
  console.log(objStingIfy)
  
  // 拼接 callback(数据) 字符串,返回给前端
  response.end(`${callback}(${objStingIfy})`)

})

app.listen(22222, () => { 
  console.log('服务启动成功!')
})

结果:

image.png

jsonp使用总结:

  • 利用 script 标签异步加载,而非传统的ajax
  • 异步 script 加载不受浏览器同源策略限制.
  • script.src=callback=fn来告知请求的后台前端提供的fn是什么
  • 基本就是前端提供方法,后端提供数据并调用前端的这个方法.
  • jsonp 只支持 get 请求.(本质上,不就是下载文件吗?下载文件一般都是get请求)

cors

corsCross-Origin-Resource-Sharing 的缩写.
也是现代浏览器普遍支持的一种非常方便的跨域方案.

它的具体工作流程是:

浏览器在检测到你发送的 ajax 请求不是同源请求时,会自动在 http 的头部添加一个 origin 字段.

image.png

之前也说过,请求怎么滴都能发送出去.

我们拿不到数据是因为浏览器在中间做了一层劫持.

image.png
image.png

获取不到数据的原因也很简单:

  • 这是一次跨域请求.
  • 请求确实发送到服务器了.
  • 服务器也把数据返回到了浏览器.
  • 但是服务器返回的响应头里,没有告诉浏览器哪个域名可以访问这些数据(也就是没有设置 Access-Control-Allow-Origin)
  • 于是浏览器就把这个数据丢弃了.我们也就无法获取到这个数据.

这个时候,只需要后台在相应头里加上一个 Access-Control-Allow-Origin:* 即可完成跨域数据获取.

image.png

CORS 跨域方案简单总结:

  • 当浏览器发送一个请求是跨域的时候,会自动加上 Origin
  • 需要后台配合设置响应头 Access-Control-Allow-Origin:*|Origin即可完成跨域.
  • CORS 支持 GET,POST 常规请求.
  • 同时也支持 PUT,DELETE等非 post,get的请求,但会先发一次预检请求.
image.png

还有一种proxy模式.

核心思想是:

让前端请求我们自己的后台,让后台去跨域请求真是的数据,然后把数据返回给前台.

实现方式,可以利用 nginx 做反向代理.以及我们自己写一个后台中转的服务器.

码云DEMO地址

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

推荐阅读更多精彩内容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,104评论 1 45
  • Section1、为什么要跨域? 自古以来(1995年起),为了用户的信息安全,浏览器就引入了同源策略。那么同源策...
    不去解释阅读 476评论 0 0
  • Section1、为什么要跨域? 自古以来(1995年起),为了用户的信息安全,浏览器就引入了同源策略。那么同源策...
    qhaobaba阅读 367评论 0 0
  • 题目1.什么是同源策略? 同源策略(Same origin Policy): 浏览器出于安全方面的考虑,只允许与本...
    FLYSASA阅读 1,663评论 0 6
  • 十几岁的时候经常见 二十岁离家过后就没见过他了 三年前,母亲重病在床 一个大雨倾盆的日子 哥哥站在门口 对着迎面而...
    闽洞秋沙阅读 465评论 4 3