Ajax专题

ajax

知识铺垫

浏览器的组成

在这里插入图片描述

  • 用户界面- 包括地址栏、后退/前进按钮、书签目录等,也就是你所看到的除了用来显示你所请求页面的主窗口之外的其他部分
  • 浏览器引擎- 用来查询及操作渲染引擎的接口
  • 渲染引擎(浏览器内核)- 用来显示请求的内容,例如,如果请求内容为 html,它负责解析 html 及 css,并将解析后的结果显示出来
  • 网络- 用来完成网络调用,例如 http 请求,它具有平台无关的接口,可以在不同平台上工作
  • UI 后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口
  • JS 解释器- 用来解释执行 JS 代码
  • 数据存储- 属于持久层,浏览器需要在硬盘中保存类似 cookie 的各种数据,HTML5 定义了 Storage 技术,这是一种轻量级完整的客户端存储技术

主流的渲染引擎

浏览器的渲染引擎也叫排版引擎,或者是浏览器内核

主流的 渲染引擎 有

  • Chrome 浏览器: Blink 引擎(WebKit 的一个分支)。
  • Safari 浏览器: WebKit 引擎,windows 版本 2008 年 3 月 18 日推出正式版,但苹果已于 2012 年 7 月 25 日停止开发 Windows 版的 Safari。
  • FireFox 浏览器: Gecko 引擎。
  • Opera 浏览器: Blink 引擎(早期版使用 Presto 引擎)。
  • Internet Explorer 浏览器: Trident 引擎。
  • Microsoft Edge 浏览器: EdgeHTML 引擎(Trident 的一个分支)。
渲染引擎的工作原理
1. 解析HTML构建Dom树,解析css为样式规则,DOM
是W3C组织推荐的处理可扩展置标语言的标准编程接口。 2.
将DOM树和样式规则构建成渲染树,渲染树并不等同于Dom树,因为像`head`标签 或
`display: none`这样的元素就没有必要放到渲染树中了,但是它们在Dom树中。 3.
对渲染树进行布局,定位坐标和大小、确定是否换行、确定position、overflow、z-index等等,这个过程叫`layout`
或 `reflow`。 4. 绘制渲染树,调用操作系统底层API(UI Backend)进行绘图操作。

在这里插入图片描述

在这里插入图片描述

服务器与客户端(浏览器)

服务器:通俗的讲,能够提供某种服务的机器(计算机)称为服务器

具有向服务器索取服务能力的终端,叫做客户端。

网络基础

通过部署后,把网页放到部署的本地服务器上后(通过使用 phpstudy)

浏览器和服务器就会有这样的交互

在这里插入图片描述

1、ip 地址

连入网络的电脑就会有一个唯一的标识,这个标识就是 IP 地址

2、端口

端口号是计算机与外界通讯交流的出口,每个端口对应不同的服务。常见端口号 80(http)、403(https)、21(ftp 文件传输协议)、22(ssh 远程登录协议)

3、域名

由于 IP 地址基于数字,不方便记忆,于是便用域名来代替 IP 地址,域名就相当于给 ip 地址起的一个名字

4、DNS 服务器

DNS(Domain Name System)因特网上作为域名和 IP 地址相互映射的一个分布式数据库, 能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的 IP 数串。简单的说就是记录 IP 地址和域名之间对应关系的服务

5、本地 host

Hosts 是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的 IP 地址建立一个关联“数据库”,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从 Hosts 文件中寻找对应的 IP 地址,一旦找到,系统会立即打开对应网页,如果没有找到,则系统会再将网址提交 DNS 域名解析服务器进行 IP 地址的解析。

完整的浏览器和服务器的交互

在这里插入图片描述

http 协议

协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则 HTTP 协议,即超文本传输协议(Hypertext transfer protocol)。是一种详细规定了浏览器和服务器之间互相通信的规则,HTTP 协议分为请求响应 两个部分组成。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <form action="server.php" method="get">
        <!-- 默认method 是get-->
      用户名: <input type="text" name="username" /> <br />
      密码: <input type="password" name="password" /><br />
      <input type="submit" value="提交" />
    </form>
  </body>
</html>

<?php
    header("content-Type:text/html;charset=utf-8");
    if($_GET["username"]=="admin" && $_GET["password"]=="123456"){
        echo "登录成功";
    }else{
        echo "登录失败";
    }
?>
GET 请求报文
-------------------------------请求行----------------------------------------
-----------------请求类型GET   url地址 + 传递的参数   http 版本号--------------
-----------GET请求的缺点:我们可以在浏览器的地址栏中看到传递的参数----------------
-----------而且因为地址栏有长度限制导致无法传递大量的参数------------------------
GET http://127.0.0.1/server.php?username=admin&password=123456 HTTP/1.1

------------------------------请求头-----------------------------------------
// Host:主机地址
Host: 127.0.0.1
// HTTP1.1版本默认开启,建立过连接后,TCP连接不会断开,下次连接可以继续使用(底层,不用管)
Connection: keep-alive
//chrome浏览器自己增加的,不用管
Upgrade-Insecure-Requests: 1
//浏览器的代理字符串(版本信息)
User-Agent: Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36
//浏览器端可以接受的类型。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
//从哪个页面发出的请求
Referer: http://127.0.0.1/http%e5%8d%8f%e8%ae%ae.html
//检查浏览器支持的压缩方式
Accept-Encoding: gzip, deflate, br
//浏览器支持的语言,优先中文。
Accept-Language: zh-CN,zh;q=0.9

--------------------------------请求体---------------------------------------
GET请求没有请求体
POST 请求报文
--------------------------------请求行----------------------------------------
------------------------请求类型 POST  url  http版本号-------------------------
POST http://127.0.0.1/server.php HTTP/1.1

---------------------------------请求头---------------------------------------
Host: 127.0.0.1
Connection: keep-alive
//传递的参数的长度。
Content-Length: 30
Cache-Control: max-age=0
Origin: http://127.0.0.1
Upgrade-Insecure-Requests: 1
//内容类型:表单数据,如果是post请求,必须指定这个属性。
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Referer: http://127.0.0.1/http%e5%8d%8f%e8%ae%ae.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
----------------------------------请求体---------------------------------------
username=admin&password=123456
POST 请求与 GET 请求的比较
  • GET 请求没有请求体,因为 GET 请求的参数拼接到地址栏中了
  • POST 请求有请求体,就是传递的参数
  • POST 请求需要指定 content-type 属性。
响应报文
-----------------------------------响应行(状态行)---------------------------------
//HTTP/1.1  HTTP版本
//200 响应的状态  状态码
//200表示成功
//304表示读缓存
//404表示找不到资源
//500表示服务端错误
HTTP/1.1 200 OK

-----------------------------------响应头-------------------------------------------
Date: Fri, 10 May 2019 12:49:50 GMT
Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.4.45
X-Powered-By: PHP/5.4.45
Content-Length: 121
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
//内容类型,告诉浏览器该如何解析响应结果
Content-Type: text/html;charset=utf-8
-----------------------------------响应体-------------------------------------------
-----------------------------服务器返回给浏览器的结果---------------------------------
<br />
<b>Notice</b>:  Undefined index: username in <b>F:\phpStudy\WWW\server.php</b> on line <b>3</b><br />
登录失败

通常来说,我们不会用抓包工具来查看请求和响应,太麻烦了,可以直接使用谷歌浏览器来查看请求报文和响应报文。

谷歌浏览器会对报文进行一定的格式化,看起来虽然不是原生的报文,但是使用起来更加的方便简洁。

Ajax

同步和异步

同步和异步概念:

同步: 指的就是事情要一件一件做。等做完前一件才能做后一件任务
异步: 不受当前任务的影响,两件事情同时进行,做一件事情时,不影响另一件事情的进行。
编程中:异步程序代码执行时不会阻塞其它程序代码执行,从而提升整体执行效率。

js 是单线程的,即 js 同一时间只能做一件事情,那么 js 是怎么实现异步操作的呢?

// js中,异步的操作: 注册的事件   定时器和延时器  ajax
// 事件循环 eventloop
/* 
  尽管js是单线程的,但是浏览器是多线程的,因此js遇到异步操作时,比如定时器,
  就会把定时器给浏览器,浏览器会把这个定时器执行的东西放在一个“任务队列中”
  当js的主线程完成后,就会去任务队列中查找是否有需要执行的,有就执行,没有就不执行,js会时不时的去任务队列中查看
  这个就是所谓的 事件循环
*/
/* 
  事件循环过程:
  1、js主线程执行代码,遇到异步的代码就把这部分交给浏览器,自己继续往后执行
  2、浏览器会把异步程序放到一个任务队列中去
  3、当js主线程执行完成,就会去任务队列里查看是否有需要执行的,有就执行,(如果是定时器,任务队列里会一直有程序在,除非清除定时器)
  这样js主线程就会时不时的去任务队列里查看
*/

ajax 发送 get 请求

// 发送一个http请求, 1. 通过表单提交  2. ajax发送
//1. 创建要给ajax对象,这个对象可以用来发送http请求,异步
var xhr = new XMLHttpRequest()

//2. 发送http请求  准备好请求三部分 (请求行, 请求头,  请求体)
// 2.1 设置请求行
// 参数1: 请求的方式  get / post
// 参数2: 请求的url地址
xhr.open('get', '05.php')

// 2.2 设置请求头
// get请求不用设置请求头

// 2.3 设置请求体
// 参数: 请求体,如果get请求,没有请求体,,传null
xhr.send(null)

ajax 发送 post 请求

// 1. 创建对象
var xhr = new XMLHttpRequest()
// 2. 设置请求报文
// 参数1: 请求的方式
// 参数2: url地址
// 2.1 设置请求行
xhr.open('post', '09.php')
// 2.2 设置请求头  post请求必须设置请求头  content-type
// content-type: 内容的类型  告诉服务端,你的发送过来的数据的类型,这里是用作表单数据进行发送
// <form action="" enctype="application/x-www-form-urlencoded"></form>
// content-type: application/x-www-form-urlencoded
// set: 设置  request:请求 header: 头
// 参数1: 请求头的名字
// 参数2: 请求头的内容
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')

// 请求体
xhr.send('username=zs&password=123456')

ajax 获取响应结果

// 获取结果
// 因为ajax是异步的操作,想要获取结果需要一定时间,如何知道结果已经获取到了
// 1. 注册一个事件
//  readystatechange : 当ajax的准备状态发生改变的时候,触发事件
xhr.onreadystatechange = function() {
  // readyState状态为4的时候,说明响应就结束
  if (xhr.readyState === 4) {
    // 1. 表示状态码 状态行
    console.log(xhr.status)
    // 2. 响应头
    console.log(xhr.getAllResponseHeaders())
    console.log(xhr.getResponseHeader('date'))
    // 3. 响应体
    // 获取响应文本
    console.log(xhr.responseText)
  }
}

readyState:记录了 XMLHttpRequest 对象的当前状态

//0:请求未初始化。
//1:请求已经建立,但是还没有开始发送。
//2:请求已发送,正在处理中
//3:请求在处理中;通常响应中已有部分数据可用了,但是服务器还没有完成响应的生成。
//4:响应已完成;您可以获取并使用服务器的响应了。(我们只需要关注状态4即可)

补充:让滚动条自动滚到底部 element.scrollIntoView()

XML 数据和 JSON 数据

XML 数据

什么是 XML

  • XML 指可扩展标记语言(EXtensible Markup Language)
  • XML 是一种标记语言,很类似 HTML
  • XML 的设计宗旨是传输数据,而非显示数据
  • XML 标签没有被预定义。您需要自行定义标签。

语法规范

  • 必须有一个根元素(有且仅有一个)
  • 标签不可有空格、不可以数字或.开头、大小写敏感
  • 不可交叉嵌套,都是双标签,如果是单标签,必须闭合
  • 属性双引号(浏览器自动修正成双引号了)
  • 注释和 HTML 一样
<students>
    <student>
        <name>张三</name>
        <age>18</age>
        <gender></gender>
        <desc>路人甲</desc>
    </student>
    <student>
        <name>李四</name>
        <age>20</age>
        <gender></gender>
        <desc>路人乙</desc>
    </student>
</students>

html 解析数据

//获取服务端返回的xml数据,需要使用xhr.responseXML,这是一个document对象,可以使用DOM中的方法查找元素。
var data = xhr.responseXML
//获取所有的学生,可以像获取DOM元素一样获取
var students = data.querySelectorAll('student')
// 在XML中是没有innerText属性的,所以获取内部文本用innerHTML或者textCOntent
var text = students.children[0].innerHTML
var text = students.children[0].textContent
JSON 数据

JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript 规范的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。

  • 数据在名称/值对中
  • 数据由逗号分隔(最后一个健/值对不能带逗号)
  • 花括号保存对象,方括号保存数组
  • 键使用双引号

JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。

var obj = { a: 'Hello', b: 'World' } //这是一个对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}' //这是一个 JSON 字符串,本质是一个字符串

JSON 与 js 对象之间的转换

  • JS 对象 ==> JSON 字符串 JSON.stringify(obj)
//obj是一个js对象
var obj = { a: 'Hello', b: 'World' }
//result就变成了一个json字符串了
var result = JSON.stringify(obj) // '{"a": "Hello", "b": "World"}'
  • JSON 字符串 ==> JS 对象 JSON.parse(obj)
//json是一个json字符串
var json = '{"a": "Hello", "b": "World"}'
//obj就变成了一个js对象
var obj = JSON.parse(json) // {a: 'Hello', b: 'World'}
eval 方法(基本不用)

eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。eval 的参数是一个字符串,这个字符串是需要执行的表达式或者语句。

console.log(eval('{}')) //undefined,因为{}备当成了代码块
console.log(eval('({})')) //obj,因为{}用()引起来了。

//使用这个方法,也可以将一个json字符串转换成js对象。
var json = '{"name":"zs", "age":18, "sex":"男"}'
var obj = eval('(' + json + ')')
console.log(obj)

封装 ajax 方法

jQuery 中也有 ajax,用$.ajax(),与我们封装的差不多的,这样我们可以用 jQuery 的 ajax

/**
 * 封装的ajax方法
 * options中包含的值
 * 参数1:type  请求的类型 get/post  默认是get
 * 参数2:url   请求的地址  必传参数
 * 参数3:data  请求的数据,传递给服务器的数据,可以是字符串或对象
 * 参数4:dataType 需要获取到的数据类型 text/ xml/ json
 * 参数5:success  响应成功时回调函数
 * 参数6:error    响应失败时回调函数
 * @param {Object} options ajax参数
 */
function ajax(options) {
  // 如果参数options没有传,或者传的值不是一个对象类型的,或者没有传递url值,直接结束
  if (!options || typeof options !== 'object' || !options.url) {
    return
  }

  // 参数处理
  var type = options.type || 'get'
  var url = options.url
  var data = options.data || null
  //   传递的data数据可以是字符串类型或者是对象类型,如果是对象 类型我们需要进行数据的拼接
  if (data && typeof data === 'object') {
    // {username: "111", password: "222"}
    // username=111&password=222
    var arr = []
    for (var k in data) {
      arr.push(k + '=' + data[k])
    }
    data = arr.join('&')
  }
  var dataType = (options.dataType || 'test').toUpperCase()
  var success = options.success
  var error = options.error

  // 开始创建ajax对象
  var xhr = new XMLHttpRequest()

  if (type === 'get' && data) {
    url = url + '?' + data
    data = null
  }
  // 设置请求行
  xhr.open(type, url)
  // 如果是POST请求设置请求头
  if (type === 'post') {
    xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
  }
  // 设置请求体
  xhr.send(data)

  // 获取响应结果
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        var result
        if (dataType === 'XML') {
          result = xhr.responseXML
        } else if (dataType === 'JSON') {
          result = JSON.parse(xhr.responseText)
        } else {
          result = xhr.responseText
        }
        success && success(result)
      } else {
        error && error()
      }
    }
  }
}
$.ajax({
	type:'', // post/get(默认是get)
	url:'',//请求的接口地址
	data:{}, // 可以传递一个对象或者一个字符串,字符串的格式  username='zs'&password='123456'
	beforeSend:function(){
		//请求发送之前会执行这个回调函数
	},
	success:function(data){
		// ajax执行成功会执行这个回调函数,返回的数据通过参数data进行返回
	},
	error:function(){
		//ajax执行报错
	},
	complete:function(){
		// ajax执行完成,不管是成功还是失败,都会执行
	}
})

模板引擎

是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的 HTML 文档。 数据+模版 = 最终需要显示的结构(动态)

我们通过 ajax 获取到数据后,需要把数据渲染到页面,在学习模板引擎前,我们的做法是大量的拼接字符串,对于结构简单的页面,这么做还行,但是如果页面结构很复杂,使用拼串的话代码可阅读性非常的差,而且非常容易出错,后期代码维护也是相当的麻烦。

str += '<li><a href="#" target="_blank">' + arr[i] + '</a></li>
ul.innerHTML = str
// 还有一种就是通过创建DOM对象来生成标签,但是总的来说,对于复杂的布局都是非常麻烦的
artTemplate 模板引擎

https://aui.github.io/art-template/zh-cn/docs/

artTemplate 的语法

/* 
  标准语法:{{}} 在{{}}中可以访问 绑定的对象中的任意属性
*/
// if语法
/*
 {{if gender='男'}}
  <div class="man">
{{else}}
  <div class="woman">
{{/if}}
 */

// each语法
/* 
  1. {{each data}}  可以通过$value 和 $index获取值和下标
  2. {{each data v i}}  自己指定值为v,下标为i
 */
/* 
{{each data v i}}
<li>
  <a href="{{v.url}}">
    <img src="{{v.src}}" alt="">
    <p>{{v.content}}</p>
   </a>
 </li>
{{/each}} 
*/

//如果返回的数据是个数组,必须使用对象进行包裹,因为在{{}}中只写书写对象的属性。
var html = template('navTmp', { data: info })

artTemplate 使用

1.引入模板引擎的 js 文件

<script src="template-web.js" />

2.准备模板

<!--
  指定了type为text/html后,这一段script标签并不会解析,也不会显示。
-->
<script type="text/html" id="myTmp">
  <p>姓名:隔壁老王</p>
  <p>年龄:18</p>
  <p>技能:查水表</p>
  <p>描述:年轻力气壮</p>
</script>

3.准备数据

//3. 准备数据,数据是后台获取的,可以随时变化
var json = {
  userName: '隔壁老王',
  age: 18,
  skill: '查水表',
  desc: '年轻气壮'
}

4.将模板与数据进行绑定

//第一个参数:模板的id
//第二个参数:数据
//返回值:根据模板生成的字符串。
var html = template('myTmp', json)
console.log(html)

5.修改模板

<script type="text/html" id="myTmp">
  <p>姓名:{{ userName }}</p>
  <p>年龄:{{ age }}</p>
  <p>技能:{{ skill }}</p>
  <p>描述:{{ desc }}</p>
</script>

6.将数据显示到页面

var div = document.querySelector('div')
div.innerHTML = html

补充知识

表单序列化 serialize

jquery 提供了一个 serialize()方法序列化表单,说白就是将表单中带有 name 属性的所有参数拼成一个格式为 name=value&name1=value1 这样的字符串。方便我们获取表单的数据。

//serialize将表单参数序列化成一个字符串。必须指定name属性
//name=cc&pass=123456&repass=123456&mobile=18511241111&code=1234
$('form').serialize()

自定义属性

H5 中定了一个规范, 所有的自定义属性都应该以 data-开头

<div
  id="box"
  class="demo"
  data-aa="bb"
  data-id="10"
  data-index="1"
  data-user="zs"
></div>
<script src="jquery.min.js"></script>
<script>
  // H5中给所有的DOM对象增加了一个属性 dataset : 所有自定义属性的集合
  var div = document.querySelector('div')
  console.log(div.getAttribute('aa'))
  console.log(div.getAttribute('data-aa'))
  console.log(div.dataset)
  console.log(div.dataset.id)
  console.log(div.dataset.aa)
  console.log($('div').attr('data-id'))
  // data只能操作 data-开头的属性

  // 缓存
  console.log($('div').data('id'))

  $('div').data('id', 100)
  console.log($('div').data('id'))
</script>

同源与跨域

同源策略的基本概念

1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。 同源策略:最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同"。

协议相同   http  https
域名相同   www.baidu.com  www.taobao.con 
端口相同   80 81 82

同源策略的目的

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

同源策略的限制范围

随着互联网的发展,“同源策略”越来越严格,目前,如果非同源,以下三种行为都将收到限制。

//1. Cookie、LocalStorage 和 IndexDB 无法读取。
//2. DOM 无法获得。
//3. AJAX 请求不能发送。

虽然这些限制是很有必要的,但是也给我们日常开发带来不好的影响。比如实际开发过程中,往往都会把服务器端架设到一台甚至是一个集群的服务器中,把客户端页面放到另外一个单独的服务器。那么这时候就会出现不同源的情况,如果我们知道两个网站都是安全的话,我们是希望两个不同源的网站之间可以相互请求数据的。这就需要使用到跨域

跨域

jsonp

JSONP(JSON with Padding)、可用于解决主流浏览器的跨域数据访问的问题。原理:服务端返回一个预先定义好的javascript函数的调用,并且将服务器的数据以该函数参数的形式传递过来,这个方法需要前后端配合。

script 标签是不受同源策略的限制的,它可以载入任意地方的 JavaScript 文件,而并不要求同源。类似的还有imglink标签

<!--不受同源策略的标签-->
<img src="http://www.api.com/1.jpg" alt="">
<link rel="stylesheet" href="http://www.api.com/1.css">
<script src="http://www.api.com/1.js"></script>

jsonp演化过程

最开始的时候,只能输出一段字符串
// 后台代码
header("content-type:text/html;charset=utf-8");
echo "alert(1111)";
// 前台调用
<script src="http://www.api.com/testjs.php"></script>

逐渐的,可以把json数据进行输出了,缺点:后端必须知道前端声明的方法的名字,后端才能调用。
// 后台代码
header("content-type:text/html;charset=utf-8");
$arr = array(
    "name"=>"zs",
    "age"=>18
);
$result = json_encode($arr);
//这是一段js函数的调用的代码,$result就是我们想要的数据
echo "func($result)";
// 前台调用
<script>
  function func(data) {
    console.log(data);
  }
</script>
<script src="http://www.api.com/testjs.php"></script>

最后就演化成了比较简洁实用,但是也因此我们必须要传一个callback参数给后台
// 后台代码
header("content-type:text/html;charset=utf-8");
$arr = array(
    "name"=>"zs",
    "age"=>18
);
$result = json_encode($arr);
//这是一段js函数的调用的代码,$result就是我们想要的数据
echo $_GET['callback']."($result)";

// 前台调用
function fun(data) {
  console.log(data);
}
var button = document.querySelector("button");
button.onclick = function () {
  var script = document.createElement("script");
  script.src = "http://www.api.com/testjs.php?callback=fun";
  document.body.appendChild(script);
}

jsonp的原理就是 借助了script标签不受同源策略的限制,在服务端返回一个函数的调用,将数据当前调用函数的实参。 在浏览器端,需要程序要声明一个函数,通过形参就可以获取到服务端返回的对应的值,必须给callback进行传值,不然后台不知道调用哪个函数,callback参数名是大家统一遵守的约定

jquery对于jsonp的封装

//使用起来相当的简单,跟普通的get请求没有任何的区别,只需要把dataType固定成jsonp即可。
$.ajax({
  type:"get",
  url:"http://www.api.com/testjs.php",
  dataType:"jsonp", 
  data:{
    uname:"hucc",
    upass:"123456"
  },
  success:function (info) {
    console.log(info);
  }
});

最后总结jsonp的原理

  1. 利用了script标签不受同源策略的影响
  2. script可以引入一段js代码,并且会执行
  3. 服务端原本直接返回json的数据, json数据当成js来执行,不合理
  4. jsonp, 服务端会给json包裹一个函数的调用,json当成函数调用的参数
  5. 浏览器端得先声明一个函数,通过形参就可以获取到调用传递的参数
  6. 一般会动态的创建script标签
  7. jsonp规定,需要给服务器端传递一个参数,callback

XMLHttpRequest2.0

老版本的XMLHttpRequest的缺点:

//1. 仅支持传输文本数据,无法传说二进制文件,比如图片视频等。
//2. 传输数据时,没有进度信息,只能提示完成与否。
//3. 受到了"同源策略"的限制

新版本的功能:

//1. 可以设置timeout超时时间
//2. 可以使用formData对象管理表单数据
//3. 允许请求不同域名下的数据(跨域)
//4. 支持上传二进制文件
//5. 可以获取数据传输的进度信息

timeout设置超时

xhr.timeout = 3000;//设置超时时间
xhr.ontimeout = function(){
  alert("请求超时");
}

formData管理表单数据

formData对象类似于jquery的serialize方法,用于管理表单数据

//使用特点: 
//1. 实例化一个formData对象, new formData(form); form就是表单元素
//2. formData对象可以直接作为 xhr.send(formData)的参数。注意此时数据是以二进制的形式进行传输。
//3. formData有一个append方法,可以添加参数。formData.append("id", "1111");
//4. 这种方式只能以post形式传递,不需要设置请求头,浏览器会自动为我们设置一个合适的请求头。

代码示例:

//1. 使用formData必须发送post请求
    xhr.open("post", "02-formData.php");

//2. 获取表单元素
var form = document.querySelector("#myForm");
//3. 创建form对象,可以直接作为send的参数。
var formData = new FormData(form);

//4. formData可以使用append方法添加参数
formData.append("id", "1111");

//5. 发送,不需要指定请求头,浏览器会自动选择合适的请求头
xhr.send(formData);

文件上传

var formData = new FormData();
//获取上传的文件,传递到后端,我们上传的文件在input对象的files中存放着
// 可以打印一下input对象查看
var file = document.getElementById("file").files[0];
formData.append("file", file);
//如果已经用form表单进行包裹了,那就可以直接用formData来获取文件就行
xhr.send(formData);

跨域资源共享(CORS)

cors的使用

新版本的XMLHttpRequest对象,可以向不同域名的服务器发出HTTP请求。这叫做"跨域资源共享"(Cross-origin resource sharing,简称CORS)。

跨域资源共享(CORS)的前提

  • 浏览器支持这个功能
  • 服务器必须允许这种跨域。

服务器允许跨域的代码:

//允许所有的域名访问这个接口
header("Access-Control-Allow-Origin:*");
//允许www.study.com这个域名访问这个接口
header("Access-Control-Allow-Origin:http://www.study.com");

CORS的具体流程(了解)

  1. 浏览器会向发送一条请求,服务器接受到请求之后,会返回请求头信息,浏览器查看返回的响应头信息中是否设置了header('Access-Control-Allow-Origin:请求源域名或者*');
  2. 如果没有设置,说明服务器不允许使用cors跨域,那么浏览器会把获取到的数据拦截。
  3. 如果返回的响应头中设置了header('Access-Control-Allow-Origin:请求源域名或者*');,浏览器会跟请求头中的Origin: http://www.study.com进行对比,如果满足要求,就把数据发送给用户。
  4. 结论:跨域行为是浏览器行为,是浏览器阻止了ajax行为。服务器与服务器之间是不存在跨域的问题的

jsonp与cors的对比

  • jsonp兼容性好,老版本浏览器也支持,但是jsonp仅支持get请求,发送的数据量有限。使用麻烦
  • cors需要浏览器支持cors功能才行。但是使用简单,只要服务端设置允许跨域,对于客户端来说,跟普通的get、post请求并没有什么区别。
  • 跨域的安全性问题:很多同学会觉得跨域能带来安全性问题,其实并不会,因为跨域是需要服务端配合的 ,也就是说不论jsonp还是cors,如果没有服务端的允许,浏览器是没法做到跨域的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值