前端基礎(chǔ)重點(diǎn)回顧4:前后端通信

同源策略及限制

同源策略的概念

  • 同源:http協(xié)議署浩,域名癣亚, 端口三者均相同
  • 同源策略是用來限制在一個(gè)源上加載的文檔或腳本與來自另一個(gè)源的資源進(jìn)行交互哺眯。這是一個(gè)用于隔離潛在惡意文件的關(guān)鍵的安全機(jī)制陕见。

同源策略的限制

  • cookie localStorage indexDB 無(wú)法讀取
  • dom 無(wú)法獲得 ajax請(qǐng)求不能發(fā)送

前后端通信的常見幾種方式

  • Ajax(同源通信)
  • WebSocket(協(xié)議不同的不同源通信)
  • CORS(用于支持不同源之間ajax通信的方法)

Ajax通信

參考

Ajax 概念

  • Ajax(Async JavaScript And XML)是一種依賴CSS/HTML/JAVASCRIPT 等現(xiàn)有技術(shù)使用XMLHttpRequest
    對(duì)象發(fā)送http 請(qǐng)求并接受響應(yīng)的一種技術(shù)方案

實(shí)現(xiàn)一個(gè)Ajax

/**
 * {string} param.url
 * {string} param.type? || 'get'
 * {object} param.data
 * {function} param.success
 * {function} param.error
 */
var ajax = function(param) {
    var xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")
    var type = (param.type ||  'get').toUpperCase()
    var url = param.url
    if(!url) return
    var data = param.data
    var dataArr = []
    for (var k in data) {
      dataArr.push(k + '=' + data[k])
    }

    if (type === 'GET') {
      url = url + '?' + dataArr.join('&')
      xhr.open(type, url)
      xhr.send()
    }

    if (type === 'POST') {
      xhr.open(type, url)
      xhr.setRequestHeader("Content-type", "application/x-www.form-urlencoded")
      xhr.send(dataArr.join('&'))
    }
    
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200 || xhr.status === 304) {
          var res
          if (param.success && typeof param.success === 'function') {
            res = xhr.responseText
            if (typeof res === 'string') {
              res = JSON.parse(res)
              param.success.call(xhr, res)
            }
          }
        } else {
          param.error.call()
        }
      }
    }
}

跨域通信的幾種方式

  • 首先我們先給host 設(shè)置幾個(gè)子域名來模擬跨域


跨域代碼示例

$ npm install
$ npm start
port: 3000 
使用示例前記得設(shè)置本機(jī)host

JSONP

jsonp 原理就是在頁(yè)面上動(dòng)態(tài)添加一個(gè)script標(biāo)簽世剖,給標(biāo)簽的src 指定一個(gè)url 路徑并加上回調(diào)函數(shù)query 參數(shù)定罢,發(fā)送給后端后,后端利用需返回的數(shù)據(jù)和回調(diào)函數(shù)的query 參數(shù)拼接成類似handleJsonp({ a:1, b:2 })的字符串返回前端旁瘫,前端定義的handleJsonp 的函數(shù)會(huì)直接運(yùn)行并處理{ a:1, b:2 } 這個(gè)后端返回的數(shù)據(jù)

  • 只能發(fā)送GET請(qǐng)求
  • 可能會(huì)被注入惡意代碼 callback=alter('111')
  • 任何域都可以發(fā)送jsonp請(qǐng)求,需進(jìn)行驗(yàn)證琼蚯,如token
// 前端代碼
      jsonpBtn.addEventListener('click', function() {
        const script = document.createElement('script')
        script.src = 'http://b.yang.com:3000/jsonp?callback=handleJsonp'
        document.head.appendChild(script)
        // document.head.removeChild(script)
      })

      function handleJsonp(data) {
        console.log(data)
      }
// 后端代碼
// JSONP
router.get('/jsonp', function(req, res, next) {
  let { callback: cb } = req.query
  const data = {
    type: 'jsonp',
    data: 'data'
  }
  cb = cb.replace(/\(/g, ''); // 替換掉() 防止惡意代碼注入
  cb = cb.replace(/\)/g, '');
  res.send(cb + '(' + JSON.stringify(data) + ')')
})

CORS

  • CORS(cross-origin resource sharing) 跨域資源共享酬凳,是一種ajax 跨域請(qǐng)求資源的方式, 普遍用于前后端分離開發(fā)環(huán)境
  • 原理就在于Access-Control-Allow-Origin 響應(yīng)頭遭庶,它指定瀏覽器在何種域下發(fā)送的ajax 請(qǐng)求服務(wù)器資源時(shí)可以跨域
  • 服務(wù)器響應(yīng)還可以設(shè)置其它header:
    1Access-Control-Allow-Methods: POST, GET, OPTIONS表明服務(wù)器允許客戶端使用 POST, GET 和 OPTIONS 方法發(fā)起請(qǐng)求
    2Access-Control-Allow-Headers: X-PINGOTHER, Content-Type表明服務(wù)器允許請(qǐng)求中攜帶字段 X-PINGOTHER 與 Content-Type
    3Access-Control-Max-Age: 86400表明該響應(yīng)的有效時(shí)間為 86400 秒
    4Access-Control-Allow-Credentials: true 表明跨域請(qǐng)求允許攜帶cookie
    MDN
// 前端代碼
     cors.addEventListener('click', function() {
        let reqHeaders = new Headers()
        reqHeaders.append('Content-Type', 'application/x-www-form-urlencoded')
        fetch('http://b.yang.com:3000/cors/', {
          method: 'post',
          headers: reqHeaders,
          mode: 'cors',
          body: 'post body'
        }).then(function (response) {
          console.log(response)
        })
      })
// 后端代碼
// CORS
router.post('/cors', function(req, res, next) {
  // res.header('Access-Control-Allow-Origin', 'http://a.yang.com:3000')
  res.header('Access-Control-Allow-Origin', '*')
  res.send('cors ok')
})

WebSocket

利用websocket 協(xié)議進(jìn)行前后端跨域通信

// 前端代碼
      var ws
      socket.addEventListener('click', function() {
        ws = new WebSocket(`ws://b.yang.com:3000/`)
        ws.onmessage = (data) => console.log(data);
        ws.onerror = () => console.log('WebSocket error');
        ws.onopen = () => console.log('WebSocket connection established');
        ws.onclose = () => console.log('WebSocket connection closed');
      })
      sendmsg.addEventListener('click', function() {
        ws.send('send a msg')
      })
// 后端代碼
var express = require('express');
var app = express();
const WebSocket = require('ws')
var server = http.createServer(app);

const wss = new WebSocket.Server({ server })
wss.on('connection', (ws, req) => {
  ws.on('message', message => {
    console.log(message)
    ws.send(message)
  })
})
server.listen(3000)

降域(使用iframe)

// URL: http://a.yang.com:3000/a
<div class="ct">
  <h1>使用降域?qū)崿F(xiàn)跨域</h1>
  <div class="main">
    <h4>URL: http://a.yang.com:3000/a</h4>
    <input type="text" placeholder="http://a.yang.com:3000/a">
  </div>
  <iframe src="http://b.yang.com:3000/b" frameborder="0" ></iframe>
</div>

<script>
  document.querySelector('.main input').addEventListener('input', function(){
    console.log(location.host, this.value);
    window.frames[0].document.querySelector('input').value = this.value;
  })
  document.domain = "yang.com"
</script>
// URL: http://b.yang.com:3000/b
<input id="input" type="text"  placeholder="http://b.yang.com:3000/b">
<script>
  document.querySelector('#input').addEventListener('input', function(){
    console.log(location.host, this.value);
    window.parent.document.querySelector('input').value = this.value;
  })
  document.domain = 'yang.com';
</script>

postMessage(使用iframe)

//URL: http://a.yang.com:3000/c
<div class="ct">
  <h1>使用postMessage實(shí)現(xiàn)跨域</h1>
  <div class="main">
    <h4>URL: http://a.yang.com:3000/c</h4>
    <input type="text" placeholder="http://a.yang.com:3000/c">
  </div>
  <iframe src="http://localhost:3000/d" frameborder="0" ></iframe>
</div>

<script>
  var input = document.querySelector('.main input')
  input.addEventListener('input', function(){
    console.log('a.yang.com - input event value', this.value);
    window.frames[0].postMessage(this.value,'*');
  })
  window.addEventListener('message',function(e) {
    input.value = e.data
    console.log('a.yang.com - message event value', e.data);
  });
</script>
// URL: http://b.yang.com:3000/d
<input id="input" type="text"  placeholder="http://b.yang.com:3000/d">
<script>
  var input = document.querySelector('#input')
  input.addEventListener('input', function(){
    console.log('b.yang.com - input event value', this.value);
    window.parent.postMessage(this.value, '*');
  })
  window.addEventListener('message',function(e) {
    input.value = e.data
    console.log('b.yang.com - message event value', e.data);
  });

</script>

其他hack

改變hash值

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宁仔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子峦睡,更是在濱河造成了極大的恐慌翎苫,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榨了,死亡現(xiàn)場(chǎng)離奇詭異煎谍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)龙屉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門呐粘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人转捕,你說我怎么就攤上這事作岖。” “怎么了五芝?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵痘儡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我枢步,道長(zhǎng)沉删,這世上最難降的妖魔是什么渐尿? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮丑念,結(jié)果婚禮上涡戳,老公的妹妹穿的比我還像新娘。我一直安慰自己脯倚,他們只是感情好渔彰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著推正,像睡著了一般恍涂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上植榕,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天再沧,我揣著相機(jī)與錄音,去河邊找鬼尊残。 笑死炒瘸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的寝衫。 我是一名探鬼主播顷扩,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼慰毅!你這毒婦竟也來了隘截?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤汹胃,失蹤者是張志新(化名)和其女友劉穎婶芭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體着饥,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡犀农,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贱勃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片井赌。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖贵扰,靈堂內(nèi)的尸體忽然破棺而出仇穗,到底是詐尸還是另有隱情,我是刑警寧澤戚绕,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布纹坐,位于F島的核電站,受9級(jí)特大地震影響舞丛,放射性物質(zhì)發(fā)生泄漏耘子。R本人自食惡果不足惜果漾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谷誓。 院中可真熱鬧绒障,春花似錦、人聲如沸捍歪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)糙臼。三九已至庐镐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間变逃,已是汗流浹背必逆。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留揽乱,地道東北人名眉。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像凰棉,于是被迫代替她去往敵國(guó)和親璧针。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355