摯愛原生之ajax——拓展跨域promise\fetch\jsonp\ascyn&await(一)

前言

關於ajax的原生實現是一個老生常談的話題,之因此再提出,一是熟悉原生寫法,二也是最重要的,跨域,衆所周知,ajax不支持跨域,這必定言爲廣大程序猿所熟知,但不少新手都只到這一層就放棄了繼續深刻的契機,再者隨着時代的發展,一系列支持跨域的websocket、ajax2.0等新特性出現,聯繫以前的jsonp,小菜決定來次小小的總結,若有紕漏望看官不吝賜教,html

========================================================= 寫着寫着發現太長了,就分段了,本文實現了原生ajax,解析SOP同源策略,解決原生AJAX跨域========================================================== 前端

本文主要實現node

  • 原生實現ajax
  • 原生ajax跨域解決
  • 跨域三劍客:websocket、ajax2.0、jsonp

正文

原生實現ajax

  • 目錄結構
  1. 用node搭建一個簡單的服務器 若不瞭解node能夠點擊下面連接,我在其中有詳細步驟 juejin.im/post/5cadc2…
const http = require('http');
const fs = require('fs');
const url = require('url');

http.createServer((req,res)=>{
    let {pathname,query} = url.parse(req.url,true);
    // console.log(pathname,query)
    //將全部要響應的數據放在data文件夾下
    pathname = `/data${pathname}`;
    //解析路徑進行判斷,若請求正確才返回
    if(pathname === '/data/data.json'){
        fs.readFile('./data/data.json',(error,buffer)=>{
            //避免返回中文亂碼
            res.writeHeader(200,{"Content-Type":"text/html;charset=utf-8"});
            res.write(buffer);
            res.end();
        })
    }else{
        res.writeHeader(404);
        res.write('NOT Found');
        res.end();
    }
   
}).listen(8080)
複製代碼
  1. 準備數據 由於只是簡單測試ajax,就不上數據庫了,建一個json文件,存些數據,包結構如上,數據以下
{
    "name":"小菜",
    "dream":"家人身體健康"
}
複製代碼
  • 此時瀏覽器直接訪問,響應以下

  1. 前端實現原生XMLHttpRequest發起請求
<script>
        const xhr = new XMLHttpRequest();
        xhr.open('get','./data.json',true);
        xhr.send();
        xhr.onreadystatechange = function(){
            // 鏈接狀態   枚舉類型 0 初始化 1 已鏈接 2 已發送 3 接收當響應頭 4 接收到響應體(即完成)
            if(xhr.readyState == 4){
                // 正則 ,意爲首位爲2的三位數   狀態碼304 也表示請求成功,只不過是告訴瀏覽器要去緩存中拿數據
                if(/^2\d\d$/.test(xhr.status) || xhr.status ==304 ){
                    //響應數據
                    alert(xhr.responseText)
                }

            }

        }
    </script>

複製代碼

這時候,若是直接打開html,就會報以下錯誤,緣由是跨域了(跨域:協議,域名,端口三者有一不一樣即爲跨域)web

這是咱們後面能解決的問題,如今先放在這,咱們先簡單的經過服務器打開html使之同源 改進版的服務端代碼,其實就是加了個html訪問接口

const http = require('http');
const fs = require('fs');
const url = require('url');

http.createServer((req,res)=>{
    let {pathname,query} = url.parse(req.url,true);
    // console.log(pathname,query)
    //將全部要響應的數據放在data文件夾下
    pathname = `/data${pathname}`;
    console.log(pathname)
    //解析路徑進行判斷,若請求正確才返回
    if(pathname === '/data/data.json'){
        fs.readFile('./data/data.json',(error,buffer)=>{
            //避免返回中文亂碼
            res.writeHeader(200,{"Content-Type":"text/html;charset=utf-8"});
            res.write(buffer);
            res.end();
        })
    }else if(pathname === '/data/index.html'){
        fs.readFile('./data/index.html',(error,buffer)=>{
            res.write(buffer);
            res.end();
        })
    }
    
    else{
        res.writeHeader(404);
        res.write('NOT Found');
        res.end();
    }
   
}).listen(8080)

複製代碼

這個時候咱們再訪問localhost:8080/index.htmlajax

就會驚訝(常理)的發現,成啦,哈哈 這個時候咱們也就實現原生的異步請求啦,可是,這不是咱們的目的,咱們如今回過頭來,找到剛剛害咱們一頓折騰的跨域報錯,同源策略數據庫

同源策源SOP

同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,若是缺乏了同源策略,則瀏覽器的正常功能可能都會受到影響。能夠說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。 ------------------------------我是分割線--------------------------------------------------- 以上解釋來自百度百科,非小菜所言json

其實就一句話:跨域請求響應回來的數據,瀏覽器會默認丟掉,並順手給你報個大大的紅錯,hhh跨域

幹啥這是?數據都不讓接

其實這正是一種安全訪問思想的體現,也正是咱們廢棄jsonp的緣由(稍後解釋);但這樣咱們若是有需求咋辦?總不可能和客戶解釋SOP吧,那會被打死;這難不倒咱們萬能的程序猿,沒有女朋友有右手,換個角度曲線救國;其實從上面的定義咱們能夠獲得一個信息:瀏覽器

  • 服務器是有響應的,只不過瀏覽器以爲會對服務器形成安全問題,就拒絕了此次響應;這也就意爲着,前臺不管作什麼,都是不可能解決原生跨域的,那怎麼辦,後臺唄,其實只要後臺響應時加上一個響應頭,聲明「這是我兄弟,放心」,就能夠了;廢話很少說,上代碼;
const http = require('http');
const fs = require('fs');
const url = require('url');

http.createServer((req,res)=>{
    let {pathname,query} = url.parse(req.url,true);
    // console.log(pathname,query)
    //將全部要響應的數據放在data文件夾下
    pathname = `/data${pathname}`;
    console.log(pathname)
    //解析路徑進行判斷,若請求正確才返回
    if(pathname === '/data/data.json'){
        fs.readFile('./data/data.json',(error,buffer)=>{
            //避免返回中文亂碼
            // res.setHeader('access-control-allow-origin', '*');
            //重點
            res.writeHeader(200,{"Content-Type":"text/html;charset=utf-8",'access-control-allow-origin':'*'});
            res.write(buffer);
            res.end();
        })
    }else if(pathname === '/data/index.html'){
        // res.setHeader();
        res.writeHeader(200,{"Content-Type":"text/html;charset=utf-8"});
        fs.readFile('./data/index.html',(error,buffer)=>{
            res.write(buffer);
            res.end();
        })
    }
    
    else{
        res.writeHeader(404);
        res.write('NOT Found');
        res.end();
    }
   
}).listen(8080)
複製代碼
  • 重點:res.writeHeader(200,{"Content-Type":"text/html;charset=utf-8",'access-control-allow-origin':'*'});
    這個時候咱們也就實現了原生跨域了,但這樣有點安全問題,我們能夠配置路由經過origin進行篩選,在這就不細說了
相關文章
相關標籤/搜索