JSONP&Promise

ECMA-JSONP&Promise

1.JS跨文件访问【需求决定需要跨域】

根据JS的引入顺序,后引入的JS可以访问先引入JS内声明的全局变量或者函数

<!-- html文件 -->
<script src="a.js"></script>
<script src="a.js"></script>

<!-- a.js文件 -->
var num = 10;
function fn(){
    console.log(666);
}

<!- b.js文件 -->
console.log(num);       // 10
fn();                   // 666

2.不受控属性和数据传输

不受控属性【src属性、href属性这2个不受同源策略影响】

根据浏览器的基本安全策略(同源策略)的控制,不同的域之间应该不可相互访问资源和内容,但是在HTML的标签中,有两个元素属性是不受同源策略的控制的,它们是src属性和href属性,这也意味着这两个属性可以加载其它网站的资源

异源数据传输

根据不受控属性的特点,我们可以通过script标签的src属性引入非同源的js文件,并获取到其中的数据,这种数据传输方式,也是jsonp跨域的来源

3.跨域

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的,广义的跨域:

  1. 资源跳转: A链接、重定向、表单提交
  2. 资源嵌入: 、

其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景

CORS(XHR2)

CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。

JSONP

JSONP(JSON with Padding)填充式JSON,是应用JSON的一种新方法,只不过是被包含在函数调用中的JSON。JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据,JSONP的基本原理是动态创建script标签,通过src属性获取异源js,从而获取到封装好的数据

4.JSONP访问百度接口

JSONP的原理

远程JS文件里面执行函数调用

本地JS文件里面函数声明

API:https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=key

<!-- html -->
<input type="text" id="key" placeholder="请输入关键字">
<ul id="oUl">
    <li>htmldda</li>
</ul>

<!-- js -->
var baidu = {
    sug: function ({ s }) { // 获取数据 解构s数组
        var html = '';
        s.forEach(item => {    // 遍历s拿到每一项
            html += `
    <li>
        <a href="https://www.baidu.com/s?wd=${item}" target="_blank">${item}</a>
    </li>`  // 拼接HTML结构
        });
        oUl.innerHTML = html;     // 将HTML插入父元素
    }
}

oKey.oninput = function () {
    if (!this.value) {          // 无输入内容时清空列表,并结束事件函数
        oUl.innerHTML = '';
        return;
    }
    var oScript = document.querySelector('#creates');   // 获取标签是否存在
    if (oScript) oScript.remove();                      // 如果存在先删除,再插入
    oScript = document.createElement('script');     // 动态创建script标签
    oScript.id = 'creates';                             // 给唯一标识,方便第二次查找
    oScript.src = `https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=${this.value}`; // 引入接口文件
    document.body.appendChild(oScript);                 // 将标签插入页面
}

5.XSS跨站攻击

XSS的概念

XSS(Cross Site Scripting)攻击全称跨站脚本攻击,为了不与CSS(Cascading Style Sheets)混淆,故将跨站脚本攻击缩写为XSS,XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。通俗的来说就是我们的页面在加载并且渲染绘制的过程中,如果加载并执行了意料之外的程序或代码(脚本、样式),就可以认为是受到了XSS攻击。XSS更多是发生在web前端的一种漏洞,所以危害的对象主要还是前端用户

image

XSS的危害

当我们知道了什么是XSS后,也一定很想知道它到底有什么用,或者有什么危害,如何防御。下面列出关于XSS有关危害:

  • 挂马
  • 盗取用户cookie
  • DOS(拒绝服务)客户端浏览器
  • 前端JS挖矿
  • 钓鱼攻击,高级的钓鱼技巧
  • 删除目标文章、恶意篡改数据、嫁祸
  • 劫持用户Web行为,甚至进一步渗透内网
  • 爆发Web2.0蠕虫
  • 蠕虫式的DDoS攻击
  • 蠕虫式挂马攻击、刷广告、刷浏量、破坏网上数据
  • 其它安全问题
XSS的分类

XSS有三类:反射型XSS(非持久型)、存储型XSS(持久型)和DOM XSS

反射型XSS

也叫非持久型XSS,交互数据一般不会被存在数据库里面,一次性,所见即所得。一般XSS代码出现在请求URL中,作为参数提交到服务器,服务器解析并响应,响应结果中包含XSS代码,最后浏览器解析并执行

场景:

  1. 用户A给用户B发送一个恶意构造了Web的URL。
  2. 用户B点击并查看了这个URL。
  3. 用户B获取到一个具有漏洞的HTML页面并显示在本地浏览器中。
  4. 漏洞HTML页面执行恶意JavaScript脚本,将用户B信息盗取发送给用户A,或者篡改用户B看到的数据等

image

一个简单的例子,我们写这么一个php接口

<?php
echo $_GET['x'];

如果输入x的值未经任何过滤就直接输出,当前端传入x=时,则alert()函数会在浏览器触发

存储型

也叫持久型XSS,主要将XSS代码提交存储在服务器端(数据库,内存,文件系统等),下次请求目标页面时不用再提交XSS代码。当目标用户访问该页面获取数据时,XSS代码会从服务器解析之后加载出来,返回到浏览器做正常的HTML和JS解析执行,XSS攻击就发生了

场景:

  1. 用户A在网页上创建了某个账户,并且账户信息中包含XSS代码。
  2. 用户B访问该网站查看XSS代码账户详情页面。
  3. 服务端返回账户详情页面,和带XSS账户信息。
  4. 用户B浏览器执行XSS代码,将用户B信息盗取发送给用户A,或者篡改用户B看到的数据等

image

DOM型

一种特殊的反射型XSS。由客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。一般从url中提取数据中含xss,未过滤并在本地执行dom的渲染操作,输入来源多是document.location、document.URL、document.URLUnencoded、document.referrer、window.location等,而触发api多是document.write()、document.writeln()、document.innerHTML、eval()、window.execScript()、window.setInterval()、window.setTimeout()等,DOM XSS和反射型XSS、存储型XSS的差别在于DOM XSS的代码并不需要服务器参与,触发XSS靠的是浏览器端的DOM解析,完全是客户端的事情

场景:

  1. 用户B访问网站url中带有XSS代码参数
  2. 浏览器下载该网站JavaScript脚本
  3. JavaScript脚本有个方法获取URL中XSS代码参数,并且用innerHTML渲染在dom中
  4. 触发XSS代码,造成XSS攻击,cookie数据失窃

image

一个简单的例子,比如我们在页面上写如下代码

<script>
    eval(location.hash.substr(1));
</script>

当你在链接的末尾加上#alert(1)的时候,页面上就会唤起弹窗,#后的内容是不会发送到服务器端的,仅仅在客户端被接收并执行

如何避免XSS攻击
  1. innerHTML(原生)、v-html(vue)、dangerouslySetInnerHTML(react)等直接渲染html的函数慎用,确保渲染的数据是由前端写死的、无危害的才可直接使用
  2. 使用innerHTML(原生)、v-html(vue)、dangerouslySetInnerHTML(react)等直接渲染html的函数渲染请求数据时,需要先把字符串转义:
    1. 把 > 替换成 >
    2. 把 < 替换成 <
    3. 把 & 替换成 &amp``;
    4. 把 " 替换成 &quot``;
    5. 把 ’ 替换成 &#39``;
  3. 字符过滤:
    1. 过滤掉特殊的HTML标签,例如
关于前端安全的思考
学习规范安全编码

根在人为,如果没有规范的学习过前端知识,特别是安全规范知识,直接跨端做前端开发的时候,很多时候知道一个功能怎么去实现,然后百度找api,找到api发现可以使用即可,通常会发生为了实现功能而忽略安全。所以我们在找到可用api时,还得查历该api是否存在安全隐患,需要如何规避、或者有其他更安全的api

对不可信数据保持敏感

对于任何非前端代码数预置数据,保持敏感对待,是否用于dom操作渲染,如果是则需要做相应的过滤处理,或者换其他安全实现方式

6.回调函数和Array.map函数的封装

回调函数

回调函数就是等会再调函数,和普通的函数不同,回调函数通常用于异步操作,函数的调用不是立即执行而是要等待一段时间,回调函数是将函数交给另一个函数去执行,但是具体的执行时间不确定,但是能确定的是,该函数一定会执行和需要等待一定的时间才会有执行结果

Array.map的封装

js手动封装map方法,完成和数组的map方法相同的功能

function map(arr, cb) {
    var list = [];                      // 定义空数组
    for (var i = 0; i < arr.length; i++) {
        var res = cb(arr[i], i, arr);   // 循环调用回调函数,并将返回值赋给res
        list.push(res);                 // 将res插入空数组中
    }   
    return list;                        // 返回操作完毕之后的数组
}

7.callback hell(回调地狱)

在我们需要对一个异步操作进行频繁的调用的时候,且要保证一步操作的顺序,可能会出现回调地狱的情况 image

8.三级接口回调地狱案例

// API1 => 根据学号查询学生班级
// API2 => 根据班级号查询学生学校
// API3 => 根据学校学校名称查询学校地址

function api1(student_id, fn) {   // API1: 学生id => 班级信息
    ajax({
        path: 'http://localhost/api1.php',
        params: {
            student_id
        },
        successCB: data => {
            fn(data);
        }
    })
}

function api2(class_num, fn) {    // API2: 班级信息 => 学校名称
    ajax({
        path: 'http://localhost/api2.php',
        params: {
            class_num
        },
        successCB: data => {
            fn(data);
        }
    })
}

function api3(school_name, fn) {    // API3: 学校名称 => 学校地址
    ajax({
        path: 'http://localhost/api3.php',
        params: {
            school_name
        },
        successCB: data => {
            fn(data);
        }
    })
}


api1('010101', data => {
    api2(data.class_num, data => {
        api3(data.school_name, data => {
            console.log(data.school_address);
        })
    })
});

9.Promise

简介

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理

特点
  1. 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。

10.Promise的使用

const requestData = function (url) {
    return new Promise(function (resolve, reject) {
        var xhr = new XMLHttpRequest();
        xhr.open('get', url);
        xhr.onload = function () {  // onreadystatechange只要返回的状态码只要变化时就回调一次函数,而onload只有状态码为4时才能回调一次函数
            if (xhr.status === 200) {
                resolve(xhr.responseText);
            } else {
                reject();
            }
        }
        xhr.onerror = function () {
            reject();
        }
        xhr.send();
    })
}

requestData(url).then(data => {}).catch(e => {});

promise实例的then方法默认返回一个成功状态的promise对象

11.Promise改写三级接口调用,链式调用

// API1: http://localhost/api1.php
// API2: http://localhost/api2.php
// API3: http://localhost/api3.php

function api1(student_id) { // 调用api1通过学生student_id获取学生班级信息
    return new Promise((resolve) => {
        ajax({
            path: 'http://localhost/api1.php',
            params: {
                student_id
            },
            successCB: data => {
                resolve(data);
            }
        })
    });
}


function api2(class_num) { // 调用api2通过学生class_num获取学校名称
    return new Promise((resolve, reject) => {
        ajax({
            path: 'http://localhost/api2.php',
            params: {
                class_num
            },
            successCB: data => {
                resolve(data);
            }
        })
    });
}

function api3(school_name) { // 调用api3通过学生school_name获取学校地址
    return new Promise((resolve) => {
        ajax({
            path: 'http://localhost/api3.php',
            params: {
                school_name
            },
            successCB: data => {
                resolve(data);
            }
        })
    });
}

api1('010101')
    .then(({ data: { class_num } }) => {
        return api2(class_num);
    })
    .then(({ data: { school_name } }) => {
        return api3(school_name);
    })
    .then(({ data: { school_address } }) => {
        console.log(school_address)
    })
         successCB: data => {
                resolve(data);
            }
        })
    });
}

api1('010101')
    .then(({ data: { class_num } }) => {
        return api2(class_num);
    })
    .then(({ data: { school_name } }) => {
        return api3(school_name);
    })
    .then(({ data: { school_address } }) => {
        console.log(school_address)
    })
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值