# Ajax网络编程
# 1. 背景知识
# 1.1 静态网页的局限性
使用以前的知识,浏览器提交数据给服务端,只能使用表单的形式提交,表单提交会造成页面刷新,影响使用体验。例如下面的登录案例,输入用户名和密码点击登录,表单提交数据给服务端,服务端返回的信息会在新页面显示,用户如果输入错误的密码需要返回重新填写。再看到使用Ajax技术实现的登录,错误信息直接显示在页面上,用户根据错误信息直接修改即可。
这就是Ajax技术需要解决的问题,解决浏览器提交/获取服务端数据刷新问题。
使用表单进行登录:
使用Ajax实现登录:
# 1.2 无处不见的Ajax
除了登录功能使用Ajax外,其实我们浏览的网站Ajax几乎是无处不见的,只要页面中存在动态变更的数据,那基本都是使用了Ajax技术获取的。
例如掘金网站的文章的“点赞”,“评论”,“翻页”功能。
# 1.3 使用chrome调试工具分析Ajax请求
打开chrome调试工具,切换到network模块,就可以看到客户端与服务端通过网络请求和接受数据的详细信息,点击左侧请求地址,就可以查看HTTP请求信息。
# 1.4 登录功能网络请求流程分析
浏览器输入http://localhost:3000/login_ajax.html 浏览器请求服务端获取login_ajax.html页面,客户端收到html内容,浏览器解析页面并渲染到浏览器上。
当输入用户名和密码点击登录,发送ajax请求服务端收到用户名密码,判断是否正确,返回“登录成功”文字。
# 2. Ajax概念与实现
# 2.1 概念
Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。
通俗说法:ajax就是一套可以让网站跟服务器交互的一种技术,能在我们需要时,不用再刷新网页就能去服务器要一些数据回来
# 2.1.1 异步与同步(重点)
先看一段代码,下面代码输出顺序为1 2 3,因为我们使用了setTimeout方法,把里面的代码延迟1秒执行,所以数字3最后输出。我们把这种非顺序执行的代码称为异步代码。
setTimeout(function() {
console.log(3);
}, 1000)
console.log(1);
console.log(2);
// 运行结果 1 2 3
另外,异步代码没法直接返回数据,只能通过回调函数获取
function sum(a,b) {
return a + b;
}
const res = sum(1,2); // res为3
// res1为undefined
const res1 = setTimeout(function() {
sum(1,2)
}, 1000);
// 通过回调函数获取
let res2;
setTimeout(function() {
res2 = sum(1,2);
console.log(res2) // 输出3
}, 1000);
console.log(res2) // 输出undefined,因为sum函数还没执行
同步:在处理一件事情时,从头做到尾,中间没有被中断
异步:在处理一件事,可以做另外一件事,再回来处理原来的事。
# 2.2 尝试发送Ajax
# 2.2.1 XHR(XMLHttpRequest)对象
XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。
发送一个get请求:
// 创建XMLHttpRequest实例
const xhr = new XMLHttpRequest();
// 调用open方法,第一个参数设置请求方式get/post;第二个参数设置请求地址
xhr.open('get', '/userLogin?username=admin&password=123456')
// 调用send方法发送请求
xhr.send();
# 2.2.2 监听返回数据
// 创建XMLHttpRequest实例
const xhr = new XMLHttpRequest();
// 调用open方法,第一个参数设置请求方式get/post;第二个参数设置请求地址
xhr.open('get', '/userLogin?username=admin&password=123456')
//-------------接收数据返回----------------------
xhr.onload = function() {
// xhr.responseText表示服务端返回的数据
document.querySelector('.error').innerHTML = xhr.responseText;
}
//-------------接收数据返回----------------------
// 调用send方法发送请求
xhr.send();
# 2.2.3 发送Ajax请求步骤
步骤:
创建异步对象,XMLHTTPRequest实例(浏览器的内置对象)
const xhr = new XMLHttpRequest();
设置请求方式和请求地址
xhr.open('get', '/userLogin?username=admin&password=123456')
监听异步对象的状态变更
xhr.onload = function() { // xhr.responseText表示服务端返回的数据 document.querySelector('.error').innerHTML = xhr.responseText; }
发送请求,根据需求传参
xhr.send();
# 2.3 实现注册功能
# 2.3.1 验证用户名是否可用
请求地址:/userLogin
请求方式:get
function validate() {
const userName = document.querySelector('#userName').value;
const tips = document.querySelector('#tips');
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://127.0.0.1:3001/validate?userName='+userName);
xhr.onload = function() {
const res = JSON.parse(xhr.responseText);
if (res.code === 200) {
tips.innerHTML = res.msg;
} else {
tips.innerHTML = res.msg;
}
}
xhr.send();
}
# 2.3.2 注册功能
function register() {
const userName = document.querySelector('#userName').value;
const userPwd = document.querySelector('#userPwd').value;
const tips = document.querySelector('#tips');
const xhr = new XMLHttpRequest();
xhr.open('post', 'http://127.0.0.1:3001/register');
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
xhr.onload = function() {
const res = JSON.parse(xhr.responseText);
if (res.code === 200) {
tips.innerHTML = res.msg;
tips.style.color = 'green';
} else {
tips.innerHTML = res.msg;
}
}
xhr.send(`userName=${userName}&userPwd=${userPwd}`);
}
POST和GET请求区别:
- 需要设置请求头。xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
- 通过send设置请求参数。xhr.send(
userName=${userName}&userPwd=${userPwd}
);
# 3. JSON数据格式
JSON(JavaScript Object Notation)是一种由道格拉斯·克罗克福特构想和设计、轻量级的数据交换语言,该语言以易于让人阅读的文字为基础,用来传输由属性值或者序列性的值组成的数据对象。
简单来说,JSON就是一种书写规范,目的是方便客户端与服务端之间交流。
# 3.1 JSON格式规范(了解,不要记忆)
- JSON 中对象的属性名称必须用双引号包裹
- JSON 中不能写注释
- JSON中数据由逗号分隔(最后一个健/值对不能带逗号)
- JSON 没有
undefined
这个值
下面是package.json文件,遵循JSON格式规范
{
"name": "docs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs"
},
"author": "",
"license": "ISC",
"dependencies": {
"vuepress": "^1.5.0"
}
}
# 3.2 JSON字符串和对象间转换
由于客户端和服务端传输数据只能是字符串或者二进制(图片、视频),而我们编写代码时使用的是JS对象,所以需要把JS对象转换为JSON字符串
// JS对象转JSON字符串
const user = {name: 'tom', age: 18};
const jUser = JSON.stringify(user);
console.log(jUser); // 输出 {"name":"tom","age":18}
服务单返回JSON字符串到浏览器后,由于需要方便读取JSON中数据,需要将JSON字符串转换为JS对象。
const userStr = '{"name":"tom","age":18}';
const user = JSON.parse(userStr);
console.log(user); // 输出 {name: "tom", age: 18}
console.log(user.name) // 输出 tom
# 3.3 Ajax请求JSON数据
// 1. 创建异步对象,XMLHTTPRequest实例(浏览器的内置对象)
const xhr = new XMLHttpRequest();
// 2. 使用open方法初始化请求对象,声明请求方式和请求地址
xhr.open('get', 'http://127.0.0.1:3001/getHero?heroName=东皇太一')
// 3. 监听异步对象的状态变更
xhr.onload = function() {
// 5. 成功获取数据,处理渲染数据
const res = xhr.responseText;
const jRes = JSON.parse(res); // ⚠️通过JSON.parse将JSON字符串转换为JS对象方便操作
}
// 4. 发送请求,根据需求传参
xhr.send();
# 4. XML数据格式(了解)
XML是一种标记语言,很类似HTML,其宗旨是用来传输数据,具有自我描述性(固定的格式的数据)。
# 4.1 XML格式规范
- xml的数据一定要设置头部 <?xml version="1.0" encoding="utf-8"?>
- xml中的标识,我们可以自己随便定义,必须有开始,就得有结束
- xml中只能有一对根标签
<?xml version="1.0" encoding="utf-8" ?>
<students>
<student>
<name>tom</name>
<age>18</age>
<gender>男</gender>
</student>
<student>
<name>tom</name>
<age>18</age>
<gender>男</gender>
</student>
</students>
JSON对应格式
{
"students": [
{ "name": "tom", "age": 18, "gender": "男" },
{ "name": "tom", "age": 18, "gender": "男" }
]
}
# 4.2 Ajax读取XML数据
- 读取服务端返回xml内容在responseXML里
- 通过getElementByTagName读取XML节点数据
// 实例化XHR对象
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://127.0.0.1:3001/getStudentsXML');
xhr.onload = function () {
// 注意,xml数据存放在responseXML中
const students = xhr.responseXML;
// 通过getElementByTagName获取xml节点数据
const id = students.getElementsByTagName('id');
console.log(id[0].innerHTML)
}
xhr.send();
# 5. 封装Ajax工具函数
封装函数的目的是为了消除重复代码,提升代码的复用率。下面我们封装一个简单的ajax方法帮助我们发送请求。
下面先对比get和post请求,找出相同的代码和不同的代码
// 发送一个get请求的代码
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://127.0.0.1:3001/validate?userName='+userName')
xhr.onload = function() {
const res = xhr.responseText;
const jRes = JSON.parse(res);
console.log(jRes)
}
xhr.send();
// ------------------------------------------------------------------------------
// 发送post请求代码
const xhr = new XMLHttpRequest();
xhr.open('post', 'http://127.0.0.1:3001/userLogin');
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.onload = function() {
const res = xhr.responseText;
const jRes = JSON.parse(res);
console.log(jRes)
}
xhr.send('username=admin&password=123456');
分析不同的代码,通过参数形式传入:
1、xhr.open时有可能是get/post,我们把这个参数叫method
2、xhr.open时,get请求参数直接拼接在后面而post请求通过send方法发送数据
3、post请求需要设置请求头
function ajax(method, url, data, success) {
const xhr = new XMLHttpRequest();
// 3、get请求参数拼接在URL后
if (method === 'get') {
url = `${url}?${data}`
}
xhr.open(method, url);
// 2、post请求需要设置请求头
if (method === 'post') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
xhr.onload = function() {
// 通过传递函数,实现不同的逻辑处理
const data = JSON.parse(xhr.responseText)
success(data);
}
// 4、post请求需要通过send方法传递
if (method === 'get') {
xhr.send();
} else {
xhr.send(data);
}
}
# 5.1 优化参数传递
刚才封装的ajax函数,在传递参数时需要传递的是字符串,例如username=admin&password=123456,当参数较多的时候手动拼接较麻烦,我们可以封装一个对象转字符串的方法帮助我们转换。
// 转换为name=tom&age=18&gender=男
function obj2str(obj) {
var result = ''
// 循环读取对象的key值和value值
for(var key in obj) {
// 获取value值
const value = obj[key];
// 拼接字符串
var str = `${key}=${value}&`
result += str;
}
// 去除最后的字符
result = result.substr(0, result.length - 1)
return result;
}
# 6. 使用jQuery发送ajax
jQueryt提供发送GET请求方法
jQuery.get(url, [data], [callback], [type])
jQueryt提供发送POST请求方法
$.post(url, [data], [callback], [dataType])
参数说明:
url: 请求URL地址
data: 发送服务端参数。
callback: 成功时回调函数。
type: 指定内容格式,如果不传递,系统会自动转换
# 6.1 对比XHR发送代码
下面是实现请求验证用户名是否使用接口的原生版本和jquery版本
// 使用xhr对象发送请求
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://127.0.0.1:3001/validate?userName='+userName')
xhr.onload = function() {
const res = xhr.responseText;
const jRes = JSON.parse(res);
console.log(jRes)
}
xhr.send();
// ------------------------------------------------------------------------------------
// 使用jquery发送
$.get('http://127.0.0.1:3001/validate', { userName }, function(data) {
console.log(jRes)
})
# 6.2 发送前拦截请求beforeSend
请求发送前的回调函数,用来修改请求发送前jqXHR对象,此功能用来设置自定义 HTTP 头信息,等等。该jqXHR和设置对象作为参数传递。这是一个Ajax事件 。在beforeSend函数中返回false将取消这个请求。
const user = $('#userName').val();
$.ajax({
type: 'post',
url: 'http://127.0.0.1:3001/validate',
data: {
userName: user
},
success: function(res) {
$('#tips').html(res.msg);
},
beforeSend: function() {
// 判断用户名是否为空
if(user === '') {
return false;
} else {
return true;
}
},
})
# 6.3 设置请求超时
当用户网路信号不佳,会出现一个网络请求长时间等待,这种情况下可以利用网络超时参数,等待超过设置时间后,提醒用户重新请求。
当请求超出时间后,可以在error回调函数提醒用户。
$.ajax({
type: 'post',
url: 'http://127.0.0.1:3001/validate',
data: {
userName: user
},
success: function(res) {
$('#tips').html(res.msg);
},
// 设置请求超时为2秒
timeout: 2000,
error: function(jqxhr, textStatus) {
if(textStatus === 'timeout') {
alert('你的网络不太好,等会再试试')
}
}
})
# 6.4 表单序列化
在实现注册功能时,获取用户名和密码需要一个个获取,当表单字段较多时会很麻烦,jquery提供名为serialize方法自动获取表单数据。
使用该方法前需要确保你获取的是一个form表单,而且表单内input字段具有name属性
<!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>表单序列化</title>
<script src="../assets/js/jquery-1.12.2.js"></script>
<script>
// 目标:理解如何使用serialize方法和其注意事项
function register() {
// 太麻烦
// const userName = $('#userName').val();
// const userPwd = $('#userPwd').val()
const form = $('form').serialize();
console.log(form) // userName=tom&userPwd=123
$.post('http://127.0.0.1:3001/register', form, function(res) {
console.log(res)
})
}
</script>
</head>
<body>
<!-- 注意点一:必须是一个表单 -->
<form action="">
<!-- 注意点二:必须有name属性 -->
用户名:<input type="text" name="userName" id="userName">
密码:<input type="password" name="userPwd" id="userPwd">
<button type="button" onclick="register()">注册</button>
</form>
</body>
</html>
# 7. 模版引擎
我们往往在ajax请求数据后需要把数据显示在页面上,例如请求学生列表数据,页面上需以表格形式显示学生信息,如果使用现有知识需使用循环和字符串拼接来实现。
看下面的案例,为了以表格的方式显示学生的数据,需要复杂的拼接,容易错误。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../assets/js/jquery-1.12.2.js"></script>
</head>
<body>
<button onclick="getStudents()">获取学生列表</button>
<div id="student"></div>
</body>
<script>
function getStudents() {
$.post('http://127.0.0.1:3001/getStudentsJSON', (res) => {
const { data } = res;
let table = '';
data.forEach(item => {
table += `<tr><th>${item.name}</th><th>${item.age}</th></tr>`
})
document.querySelector('#student').innerHTML = `<table border="1"><tr><th>姓名</th><th>年龄</th></tr>${table}</table>`
})
}
</script>
</html>
# 7.1 art-template使用
art-template模版引擎就像jQuery一样,是一个工具库,解决字符串+数据渲染问题,虽然有ES6的模版字符串,但是如果需要实现循环输出,逻辑判断,ES6的模版字符串就显得单薄。
使用步骤:
页面引入template-web.js
定义模版,注意type为text/html 还有有唯一id。
<script type="text/html" id="user"> 我的名字叫{{name}}, 今年{{age}}岁, template </script>
通过template方法传入模版id和数据
const html = template('user', user)
完整代码
<!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>art-template输出</title> <!-- 引入art-template资源 --> <script src="../assets/js/template-web.js"></script> <script type="text/html" id="user"> 我的名字叫{{name}},年龄{{age}}岁 </script> </head> <body> <div id="result"></div> <script> const user = { name: 'tom', age: 18 } // template('模板id', 数据) const result = template('user', user ); document.querySelector('#result').innerHTML = result; </script> </body> </html>
# 7.2 模版语法
art-template 支持标准语法与原始语法。标准语法可以让模板易读写,而原始语法拥有强大的逻辑表达能力。
标准语法支持基本模板语法以及基本 JavaScript 表达式;原始语法支持任意 JavaScript 语句,这和 EJS 一样。
原生语法只做了解即可。
# 7.2.1 输出
用于显示元素到页面
// 标准语法,使用花括号包裹,可以执行运算符
{{value}}
{{data.key}}
{{data['key']}}
{{a ? b : c}}
{{a || b}}
{{a + b}}
// 原生语法 <%= 变量名%>
<%= value %>
<%= data.key %>
<%= data['key'] %>
<%= a ? b : c %>
<%= a || b %>
<%= a + b %>
# 7.2.2 循环语法
// 标准语法,target表示需要迭代的对象或者数组
{{each target}}
// $index表示循环的下标,$value表示当前下标的数据
{{$index}} {{$value}}
{{/each}}
// 原生语法
<% for(var i = 0; i < target.length; i++){ %>
<%= i %> <%= target[i] %>
<% } %>
例如要渲染学生数据
// 标准语法
{{each data student idx}}
<div>名字:{{student.name}},年龄:{{student.age}}, 性别:{{student.gender}}</div>
{{/each}}
// 原生语法
<% for(var i = 0; i < data.length; i++){ %>
<div>名字:<%= data[i].name%>,年龄:<%= data[i].age%>, 性别:<%= data[i].gender%></div>
<% } %>
# 7.2.3 条件判断
// 标准语法
{{if value}} ... {{/if}}
{{if v1}} ... {{else if v2}} ... {{/if}}
// 原生语法
<% if (value) { %> ... <% } %>
<% if (v1) { %> ... <% } else if (v2) { %> ... <% } %>
循环输出学生数据,判断性别,如果是男字体显示绿色,女显示红色
// 标准语法
{{each data student idx}}
{{if student.gender === '男'}}
<div style="color: green">名字:{{student.name}},年龄:{{student.age}}, 性别:{{student.gender}}</div>
{{else}}
<div style="color: red">名字:{{student.name}},年龄:{{student.age}}, 性别:{{student.gender}}</div>
{{/if}}
{{/each}}
// 原生语法
<% for(var i = 0; i < data.length; i++){ %>
<% if (data[i].gender === '男') { %>
<div style="color: green">名字:<%= data[i].name %>,年龄:<%= data[i].age %>, 性别:<%= data[i].gender %></div>
<% } else { %>
<div style="color: red">名字:<%= data[i].name %>,年龄:<%= data[i].age %>, 性别:<%= data[i].gender %></div>
<% } %>
<% } %>
# 8. XMLHttpRequest 2.0
XMLHttpRequest2.0是XHR的新版本,针对老版本的XHR对象的问题作出了很多的改进。XHR2.0发布于2008年,现代浏览器基本都支持XHR2.0的特性,大家可以放心使用。如果你要支持IE10以下的浏览器,就要注意该特性在IE下的最低要求版本了。
# 8.1 请求超时timeout属性
用于设置请求超时,可以在ontimeout方法处理超时逻辑
function getJoke() {
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://127.0.0.1:3001/getJoke?jokeId=1');
xhr.timeout = 2000; // 表示设置两秒钟超时
// 请求超时处理
xhr.ontimeout = function() {
alert('请求超时')
}
xhr.onLoad = function() {
console.log(xhr.responseText)
}
xhr.send();
}
# 8.2 FormData对象
ajax操作往往用来传递表单数据。为了方便表单处理,HTML 5新增了一个FormData对象,可以模拟表单。但是FormData对象发送数据给服务端时以二进制的形式发送,多用于上传文件/图片。
下面例子演示如何通过FormData对象自动获取表单用户名和密码,大家可以注意打开chrome network查看发送的请求头 Content-Type为multipart/form-data;
<!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">
<script>
function register() {
// 创建formdata
const form = document.querySelector('form');
const formData = new FormData(form); // 创建formData对象
// 发送ajax
const xhr = new XMLHttpRequest();
xhr.open('post', 'http://127.0.0.1:3001/register');
// xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')// 因为我们以二进制形式提交,不需要进行编码
xhr.onload= function() {
console.log(xhr.responseText)
}
// 以二进制传递
xhr.send(formData)
}
</script>
</head>
<body>
<form>
用户名:<input type="text" name="userName" id="userName" />
密码:<input type="text" name="userPwd" id="userPwd" />
<input type="button" value="注册" onclick="register()">
</form>
</body>
</html>
# 8.3 上传文件
# 8.3.1 使用FormData上传图片
<!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>原生图片上传</title>
<style>
.progress {
width: 0%;
height: 20px;
background-color: lime;
}
</style>
<script>
function uploadImg() {
const xhr = new XMLHttpRequest();
xhr.open('post', 'http://127.0.0.1:3001/uploadFile')
xhr.onLoad = function() {
const res = JSON.parse(xhr.responseText);
document.querySelector('#result').src = res.src;
}
// 获取图片
const file = document.querySelector('#image').files[0];
const formData = new FormData()
formData.append('avatar', file) // 给formdata对象添加属性
xhr.send(formData);
}
</script>
</head>
<body>
<!-- onchange事件,表示用户选择文件后调用 -->
<input type="file" name="image" id="image" onchange="uploadImg()">
<img id="result" src="" alt="">
<div class="progress"></div>
</body>
</html>
# 8.3.2 显示上传进度
// 显示上传进度
xhr.upload.onprogress = function(event) {
// 判断是否可以计算进度
if (event.lengthComputable) {
// 计算百分比 event.loaded / event.total 0.9874876443501531
// 乘100,去掉末尾小数
const uploadPercent = parseInt((event.loaded / event.total) * 100) + '%';
document.querySelector('.progress').style.width = uploadPercent;
document.querySelector('.progress').innerHTML = uploadPercent;
}
}
# 8.3.3 使用jquery上传图片
<!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>jquery上传图片</title>
<script src="../assets/js/jquery-1.12.2.js"></script>
<script>
function uploadImg() {
// 获取用户图片
const file = $('#image')[0].files[0];
// 创建formdata对象
const formdata = new FormData();
formdata.append('avatar', file)
$.ajax({
type: 'post',
url: './uploadFile',
data: formdata,
contentType: false, // 禁止进行编码
processData: false, // 禁止对数据进行处理,因为我们的是二进制数据
success: function(res) {
const jRes = JSON.parse(res)
$("#uploadImg").attr('src', jRes.src);
},
// 重新设置xhr对象,获取上传进度
xhr: function () {
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
const uploadPercent = parseInt((event.loaded / event.total) * 100) + '%';
}
}
return xhr;
},
})
}
</script>
</head>
<body>
<input type="file" name="image" id="image" onchange="uploadImg()">
<img id="uploadImg" src="" alt="">
</body>
</html>
# 8.4 跨域
浏览器出于安全需要,实现了同源策略。同源策略限制浏览器不同源间资源的访问,例如cookie,localstorage,而且不同源间ajax请求无法发送。
# 8.4.1 怎么才算不同源
例如我们访问的页面是:http://127.0.0.1/index.html
检查协议、域名、端口,如果和访问地址有区别即认为不同源,下面三个地址均为不同源
协议:https://127.0.0.1/index.html
域名不同/ip地址:http://127.0.0.2/index.html
端口:http://127.0.0.1:3000/index.html
# 8.4.2 对不同源发送ajax请求
对不同源发送ajax请求,浏览器会提示下图红色的错误。
# 8.4.3 跨域解决方法
服务端设置响应头Access-Control-Allow-Origin:*(推荐使用)
var server = http.createServer((req,res) => { res.setHeader('access-control-allow-origin', '*'); // 关键代码 })
设置完毕后,发起ajax请求查看该请求的响应头,会出现下图,表示设置成功。
服务器代理请求(较少使用)
服务器代理模式相当于,你需要购买国外的一件商品,你因为没法出国购买,这时候你可以委托别人旅游的时候帮你带一件回来,这个委托人就相当于代理服务器。
JSONP(不推荐使用,了解即可)
<script>
function success(res) {
console.log(res)
}
</script>
<!-- JSONP需要服务端配置实现 -->
<script src="http://127.0.0.1:5001/getStudentsJSONP.js?callback=success"></script>