Ajax简介
Asynchronous JavaScript And XML:在不网页无刷新跳转的情况下,向服务器(后端)发送HTTP请求并得到HTTP响应
Ajax就是一个异步无刷新请求,无需更新整个页面就异步加载一些数据,交互性更强。
Ajax优缺点
- 无需刷新页面即可与服务器端进行通信。
- 允许根据用户事件来更新部分页面内容。
- 无浏览历史,不能回退。
- 存在跨域问题(同源):如
a.com
向b.com
发送AJAX请求默认是不可行的。- SEO(Search Engine Optimization)不友好。
如何使用Ajax?
- 原生
- JQuery
- fetch函数
- axios工具包
XML简介
可扩展标记语言(eXtensible Markup Language)。
与HTML的区别?
XML 被设计用来传输和存储数据,其焦点是数据的内容;HTML 被设计用来显示数据,其焦点是数据的外观。
(1)可扩展性方面:HTML不允许用户自行定义他们自己的标识或属性,而在XML中,用户能够根据需要自行定义新的标识及属性名,以便更好地从语义上修饰数据。
(2)结构性方面:HTML不支持深层的结构描述,XML的文件结构嵌套可以复杂到任意程度,能表示面向对象的等级层次。
(3)可校验性方面:HTML没有提供规范文件以支持应用软件对HTML文件进行结构校验,而XML文件可以包括一个语法描述,使应用程序可以对此文件进行结构校验。
AJAX的数据传输格式现在已经逐渐被JSON取代。
HTTP相关问题
- 应用从浏览器端向服务器发送HTTP请求(请求报文)
- 后台服务器接收到请求后, 调度服务器应用处理请求, 向浏览器端返回HTTP响应(响应报文)
- 浏览器端接收到响应, 解析显示响应体/调用监视回调
- HTTP请求报文
请求行 method URL 协议版本
如:POST /s?ie=utf-8 HTTP/1.1
---
请求头
Host: baidu.com
Cookie: BAIDUID=AD3B0FA706E; BIDUPSID=AD3B0FA706;
Content-Type: application/x-www-form-urlencoded # 或者application/json
User-Agent: chrome ...
...
---
请求体
username=tom&pwd=123 # or {"username": "tom", "pwd": 123}
- HTTP响应报文
响应状态行 status statusText
如:200 OK
---
响应头
Content-Type: text/html?charset=utf-8
Content-Length: 2048
Content-encoding: gzip
...
响应体
# HTML代码/json文本/js/css/图片
- POST请求体参数格式
Content-Type: application/x-www-form-urlencoded;charset=utf-8
# 用于键值对参数,参数的键值使用“=”连接,参数之间使用“&”连接
如:name=小小&age=11
---
Content-Type: application/json;charset=utf-8
# 用于json字符串参数
如:{"name": "小小","age":11}
---
Content-Type: multipart/form-data
# 用于文件上传请求
常见的响应状态码
200 OK
请求成功。一般用于GET 与POST 请求
201 Created
已创建。成功请求并创建了新的资源
401 Unauthorized
未授权/请求要求用户的身份认证
404 Not Found
服务器无法根据客户端的请求找到资源
500 Internal Server Error
服务器内部错误,无法完成请求
不同类型的请求及其作用
GET
: 从服务器端读取数据(查)POST
: 向服务器端添加新数据 (增)PUT
: 更新服务器端已经数据 (改)DELETE
: 删除服务器端数据 (删)
API 的分类
-
REST API: restful (Representational State Transfer (资源)表现层状态转化)
(1) 发送请求进行CRUD 哪个操作由请求方式来决定
(2) 同一个请求路径可以进行多个操作
(3) 请求方式会用到GET/POST/PUT/DELETE -
非REST API: restless
(1) 请求方式不决定请求的CRUD 操作
(2) 一个请求路径只对应一个操作
(3) 一般只有GET/POST
http请求与ajax请求的区别
- ajax请求是一种特别的 http请求
- 对服务器端来说,,没有任何区别, 区别在浏览器端
- 浏览器端发请求:只有
XHR
或fetch
发出的才是ajax 请求,其它所有的都是非ajax 请求 - 浏览器端接收到响应
(1) 一般请求:浏览器一般会直接显示响应体数据, 也就是我们常说的刷新/跳转页面
(2) ajax请求:浏览器不会对界面进行任何更新操作, 只是调用监视的回调函数并传入响应相关数据
原生AJAX:使用 XHR
XHR(XMLHttpRequest)用于与服务器交互数据,是AJAX功能实现所依赖的对象,JQuery中的AJAX就是对XHR的封装。
XMLHttpRequest 对象提供了对 HTTP 协议的完全的访问,包括做出 POST 和 HEAD 请求以及普通的 GET 请求的能力。XMLHttpRequest 可以同步或异步地返回 Web 服务器的响应,并且能够以文本或者一个 DOM 文档的形式返回内容。
XHR接口强制要求每个请求都具备严格的HTTP语义–应用提供数据和URL,浏览器格式化请求并管理每个连接的完整生命周期,所以XHR仅仅允许应用自定义一些HTTP首部,但更多的首部是不能自己设定的,如:
Accept-Charset, Accept-Encoding, Access-Control-* Host, Upgrade, Connection, Referer, Origin Cookie, Sec-, Proxy-, 及其他首部
准备工作
个人觉得 node.js(执行.js文件的JavaScript代码)和 npm 有些类似 python 解释器和 pip 包管理工具的关系。
-
安装
node.js
Node.js发布于2009年5月,是一个基于Chrome V8引擎的JavaScript【事件驱动脚本语言】运行环境,使用了一个事件驱动、非阻塞式I/O模型, 让JavaScript 运行在服务端的开发平台。
简单的说 Node.js 就是运行在服务端的 JavaScript
Node可以在不新增额外线程的情况下,依然可以对任务进行并发处理 —— Node.js是单线程的。它通过事件循环(event loop)来实现并发操作,对此,我们应该要充分利用这一点 —— 尽可能的避免阻塞操作,取而代之,多使用非阻塞操作。
安装地址:http://nodejs.cn/
-
第一个程序
Node.js 应用组成部分:
- 引入 required 模块:使用 require 指令来载入 Node.js 模块。
- 创建服务器:服务器可以监听客户端的请求,类似于 Apache 、Nginx 等 HTTP 服务器。
- 接收请求与响应请求 :服务器很容易创建,客户端可以使用浏览器或终端发送 HTTP 请求,服务器接收请求后返回响应数据。
在项目的根目录下创建一个叫
server.js
的文件,写入以下代码:var http = require('http'); http.createServer(function (request, response) { // 发送 HTTP 头部 // HTTP 状态值: 200 : OK // 内容类型: text/plain response.writeHead(200, {'Content-Type': 'text/plain'}); // 发送响应数据 "Hello World" response.send('Hello World\n'); }).listen(8888); // 终端打印如下信息 console.log('Server running at http://127.0.0.1:8888/');
以上代码我们完成了一个可以工作的 HTTP 服务器。使用
node
命令执行以上的代码:node server.js ## Server running at http://127.0.0.1:8888/
-
NPM
NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:
- 允许用户从NPM服务器下载别人编写的第三方包到本地使用。
- 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
- 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
由于新版的nodejs已经集成了npm,所以之前npm也一并安装好了。同样可以通过输入 “npm -v” 来测试是否成功安装。
-
安装express(web框架模块)
Express中文网:https://www.expressjs.com.cn/
nodeJS相关和npm使用参考:https://www.runoob.com/nodejs/nodejs-npm.html
- 初始化环境(在项目根目录下)
npm init --yes
- 安装express模块(项目路径下)
npm install express --save npm install express -g --save # 全局
- 编写js代码
// 1. 引入express const express = require('express'); // 2. 创建应用对象 const app = express(); // 3. 创建路由规则 // request 是对请求报文的封装 // response 是对响应报文的封装 app.get('/', (request, response) => { // 设置响应 response.send("Hello Express"); }); // 4. 监听端口,启动服务 app.listen(8000, () => { console.log("server is running on http://127.0.0.1:8000/"); })
- 运行程序
-
安装nodemon自动重启工具
文件内容有修改自动重新启动服务:https://www.npmjs.com/package/nodemon
安装
npm install -g nodemon
启动服务
ndoemon server.js
注意点:
- 使用
XMLHttpRequest
(XHR)对象可以与服务器交互, 也就是发送ajax 请求 - 前端可以获取到数据,而无需让整个的页面刷新。(使得Web 页面可以只更新页面的局部,而不影响用户的操作)
XHR文档:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest。
AJAX 的所有操作都是通过该对象进行的
核心对象使用步骤
-
创建XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
-
设置请求信息(请求方法和url)
// 请求方式 xhr.open(method, url); //可以设置请求头,一般不设置 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 自定义请求头 xhr.setRequestHeader('name', 'moonjay'); // 自定义请求头需要在server.js加入 response.setHeader('Access-Control-Allow-Headers', '*');
-
发送请求
xhr.send(body) //get请求不传 body 参数,只有post请求使用
-
接收响应(事件绑定,处理服务端返回的结果)
//xhr.responseXML 接收 xml格式 的响应数据 //xhr.responseText 接收 文本格式 的响应数据 xhr.onreadystatechange = function(){ // readyState 是 xhr对象中的属性, 表示状态 0 1 2 3 4 if(xhr.readyState == 4 && xhr.status == 200){ var text = xhr.responseText; console.log(text); } }
AJAX 请求状态
xhr.readyState
可以用来查看请求当前的状态
文档链接:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/readyState
- 0: 表示XMLHttpRequest 实例已经生成,但是open()方法还没有被调用
- 1: 表示send()方法还没有被调用,仍然可以使用setRequestHeader(),设定HTTP请求的头信息
- 2: 表示send()方法已经执行,并且头信息和状态码已经收到
- 3: 表示正在接收服务器传来的body 部分的数据
- 4: 表示服务器数据已经完全接收,或者本次接收已经失败了
示例
-
GET 请求(点击返回响应信息)
文件结构(浏览器端–html文件;服务器端–js文件)
server.js
:// 1. 引入express const express = require('express'); // 2. 创建应用对象 const app = express(); // 3. 创建路由规则 app.get('/server', (request, response) => { // 设置响应头 设置允许跨域 response.setHeader('Access-Control-Allow-Origin', '*'); // 设置响应体 response.send("Hello Ajax"); }); // 4. 监听服务 app.listen(8000, () => { console.log("server is running on http://127.0.0.1:8000/"); })
01Get.html
:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Ajax GET 请求</title> <style> #result { width: 200px; height: 100px; border: solid 1px #90b; } </style> </head> <body> <button>点击发送请求</button> <div id="result"></div> <script> //获取button元素 const btn = document.getElementsByTagName('button')[0]; const result = document.getElementById('result'); //绑定事件 btn.onclick = function(){ // 1. 创建对象 const xhr = new XMLHttpRequest(); // 2. 初始化 设置请求方法和url xhr.open('GET', 'http://127.0.0.1:8000/server') // 3. 发送, GET不发送body POST发送 xhr.send(); // 4. 事件绑定 处理服务端返回的结果 xhr.onreadystatechange = function(){ // readyState 是 xhr 对象中的属性, 表示状态 0 1 2 3 4 //判断 (服务端返回了所有的结果) if(xhr.readyState === 4){ //判断响应状态码 200 404 403 401 500 if(xhr.status >= 200 && xhr.status < 300){ // 处理结果 行 头 空行 体 // 响应行 console.log('状态码', xhr.status); // 状态码 console.log('状态字符串', xhr.statusText); // 状态字符串 console.log('所有响应头', xhr.getAllResponseHeaders()); // 所有响应头 console.log('响应体', xhr.response); // 响应体 //设置 result 的文本 result.innerHTML=xhr.response; }else{ } } } } </script> </body> </html>
GET 请求设置请求参数
xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');
可以在Headers中看到Query String Parameters多出三个参数
-
POST请求(鼠标放到div中,发post请求,将响应体放在div中呈现)
server.js
添加POSTapp.post('/server', (request, response) => { // 设置响应头, 设置允许跨域 response.setHeader('Access-Control-Allow-Origin', '*'); // 设置响应体 response.send("Hello Ajax POST"); });
01Post.html
:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Ajax POST 请求</title> <style> #result { width: 200px; height: 100px; border: solid 1px #903; } </style> </head> <body> <div id="result"></div> <script> // 获取元素对象 const result = document.getElementById('result'); // 绑定事件 result.addEventListener("mouseover", function(){ // 1. 创建对象 const xhr = new XMLHttpRequest(); // 2. 初始化 设置类型(请求方式)与url xhr.open('POST', 'http://127.0.0.1:8000/server'); // 3. 发送 设置请求参数(请求体),可以说任意类型的 xhr.send('a=100&b=200&c=300'); // 4. 事件绑定 xhr.onreadystatechange = function(){ // 判断 if(xhr.readyState === 4){ if(xhr.status >=200 && xhr.status < 300){ // 处理服务端返回的结果 result.innerHTML = xhr.response; } } } }); </script> </body> </html>
JSON数据请求
server.js
中设置响应头允许自定义请求头post改成all
// app.all() -- 可以get、post
app.all('/json-server', (request, response) => {
// 设置响应头, 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应头, 设置允许自定义头信息
response.setHeader('Access-Control-Allow-Headers', '*');
// 响应一个数据
const data = {
name: 'moonjay'
};
// 对 对象 进行 字符串 转换
let str = JSON.stringify(data)
// 设置响应体
response.send(str);
});
01JSON.html
:(按下键盘任意按键触发)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSON</title>
<style>
#result {
width: 200px;
height: 100px;
border: solid 1px #89b;
}
</style>
</head>
<body>
<div id="result"></div>
<script>
const result = document.getElementById('result');
// 绑定键盘按下事件
window.onkeydown = function(){
// 发送请求
const xhr = new XMLHttpRequest();
// *2*.(自动转换) 设置响应体数据的类型(自动转换)
xhr.responseType = 'json';
// 初始化
xhr.open('GET', 'http://127.0.0.1:8000/json-server');
// 发送
xhr.send();
// 事件绑定
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.response);
// 1. 手动对数据转化 (字符串再转换成json)
// let data = JSON.parse(xhr.response); //转换成json
// result.innerHTML = data.name;
// 2. 自动转换
result.innerHTML = xhr.response.name; //已经自动变成json
}
}
}
}
</script>
</body>
</html>
请求超时与网络异常
// 超时设置 (2秒)
xhr.timeout = 2000;
// 超时回调
xhr.ontimeout = function(){
alert('网络超时,请稍后重试')
}
// 网络异常回调 在chrome’检查‘的Network选项卡可以设置网络环境--设为offline
xhr.onerror = function(){
alert('网络异常,请稍后重试')
}
// 手动取消请求
xhr.abort()
在server.js
中设置:
app.get('/delay', (request, response) =>{
response.setHeader('Access-Control-Allow-Origin', '*');
setTimeout(() => {
response.send('延时响应');
}, 3000)
});
重复请求问题
用户可能重复向服务器发送相同请求,造成服务器端响应压力,如何解决?
创建一个只有一个按钮的html网页,html代码略,下为script脚本:
const btn = document.querySelector('button')
let x = null;
// 标识变量 是否正在发送AJAX请求
let isSending = false;
btn.onclick = function(){
// 判断标识变量,如果正在发送,则取消该请求创建一个新的请求
if(isSending) x.abort();
x = new XMLHttpRequest();
// 修改标识变量的值
isSending = true;
x.open("GET", "http://127.0.0.1:8000/delay");
x.send();
x.onreadystatechange = function(){
if(x.readyState === 4){
//修改标识变量
isSending = false;
}
}
}
IE 缓存问题
问题:在一些浏览器中(IE),由于缓存机制的存在,ajax 只会发送的第一次请求,剩余多次请求不会在发送给浏览器而是直接加载缓存中的数据。
解决方式:浏览器的缓存是根据url 地址来记录的,所以我们只需要修改url 地址即可避免缓存问题。
xhr.open("get","/testAJAX?t="+Date.now());
API总结
XMLHttpRequest()
:创建 XHR 对象的构造函数status
:响应状态码值,如 200、404statusText
:响应状态文本,如 ’ok‘、‘not found’readyState
:标识请求状态的只读属性 0-1-2-3-4onreadystatechange
:绑定 readyState 改变的监听responseType
:指定响应数据类型,如果是 ‘json’,得到响应后自动解析响应response
:响应体数据,类型取决于 responseType 的指定timeout
:指定请求超时时间,默认为 0 代表没有限制ontimeout
:绑定超时的监听onerror
:绑定请求网络错误的监听open()
:初始化一个请求,参数为:(method, url[, async])
send(data)
:发送请求abort()
:中断请求 (发出到返回之间)getResponseHeader(name)
:获取指定名称的响应头值getAllResponseHeaders()
:获取所有响应头组成的字符串setRequestHeader(name, value)
:设置请求头
JQuery中的AJAX
get 请求
$.get(url, [data], [callback], [type])
post 请求
$.post(url, [data], [callback], [type])
- url:请求的URL 地址
- data:请求携带的参数
- callback:载入成功时回调函数
- type:设置返回内容格式,xml, html, script, json, text, _default
通用方法
$.ajax({
// url
url: 'http://127.0.0.1:8000/jquery-server',
// 参数
data: {a:100, b:200},
// 请求类型
type: 'GET',
// 响应体结果
dataType: 'json',
// 成功的回调
success: function(data){console.log(data);},
// 超时时间
timeout: 2000,
// 失败的回调
error: function(){console.log('出错la~');},
// 头信息
headers: {
c: 300,
d: 400
}
})
示例
JQuery_AJAX.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JQuery发送Ajax请求</title>
<!--crossorigin="anonymous"是跨域匿名请求的意思,向css或js文件发送请求时不会携带当前站点的cookies-->
<link crossorigin="anonymous" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap-theme.min.css" rel="stylesheet">
<script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</head>
<body>
<div class="container">
<h2 class="page-header">JQuery发送Ajax请求</h2>
<button class="btn btn-primary">GET</button>
<button class="btn btn-danger">POST</button>
<button class="btn btn-info">通用型方法Ajax</button>
</div>
</body>
<script>
$('button').eq(0).click(function(){
$.get('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){
console.log(data)
}, 'json'); //响应体类型为json
})
$('button').eq(1).click(function(){
$.post('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){
console.log(data)
}); //响应体类型为字符串
})
$('button').eq(2).click(function(){
$.ajax({
// url
url: 'http://127.0.0.1:8000/jquery-server',
// 参数
data: {a:100, b:200},
// 请求类型
type: 'GET',
// 响应体结果--可选,默认为字符串
dataType: 'json',
// 成功的回调
success: function(data){console.log(data);},
// 超时时间
timeout: 2000,
// 失败的回调
error: function(){console.log('出错la~');},
// 头信息
headers: {
c: 300,
d: 400
}
});
})
</script>
</html>
server.js
加入以下代码:
// JQuery_AJAX.html文件用 all--可以响应get和post
app.all('/jquery-server', (request, response) => {
// 设置响应头
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应头, 设置允许自定义头信息,
// 第3个按钮有头信息参数,不设置会出错
response.setHeader('Access-Control-Allow-Headers', '*');
// response.send("hello JQuery AJAX");
// 响应体类型为json
const data = {name: "moonjay"};
response.send(JSON.stringify(data))
});
axios发送AJAX请求
axios的Github链接:https://github.com/axios/axios
是一个基于promise的网络请求库,作用于node.js和浏览器中,它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生node.js http模块, 而在客户端 (浏览端) 则使用XMLHttpRequest。
axios本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范。
主要特点:
- 从浏览器创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF
- 🆕 Automatic data object serialization to
multipart/form-data
andx-www-form-urlencoded
body encodings
使用npm安装:
npm install axios
HTML页面引用CDN链接:
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!--or-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
GET、POST、通用方法
参考链接:https://github.com/axios/axios#request-method-aliases
axios.get(url[, config])
axios.post(url[, data[, config]])
axios()
示例
server.js
文件加入以下代码:
// axios_ajax.html文件用
app.all('/axios-server', (request, response) => {
// 设置响应头
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应头, 设置允许自定义头信息,
// 第3个按钮有头信息参数,不设置会出错
response.setHeader('Access-Control-Allow-Headers', '*');
// response.send("hello axios AJAX");
// 响应体类型为json
const data = {name: "moonjay axios"};
response.send(JSON.stringify(data))
});
axios_Ajax.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>axios发送Ajax请求</title>
<link crossorigin="anonymous" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap-theme.min.css" rel="stylesheet">
<script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.js"></script>
</head>
<body>
<div class="container">
<h2 class="page-header">axios发送Ajax请求</h2>
<button class="btn btn-primary">GET</button>
<button class="btn btn-danger">POST</button>
<button class="btn btn-info">Ajax</button>
</div>
</body>
<script>
const btns = document.querySelectorAll('button');
//配置 baseURL
axios.defaults.baseURL = 'http:127.0.0.1:8000'
btns[0].onclick = function(){
//GET请求
axios.get("/axios-server", {
// url参数
params:{
id: 100,
vip: 7
},
//请求头信息
headers:{
name: "moonjay",
age: 20
}
}).then(value => {
console.log(value);
});
}
btns[1].onclick = function(){
//POST请求
axios.post("/axios-server",
// 请求体 第2个参数
{
username: "admin",
pwd: 123456
},
{
// url参数
params:{
id: 101,
vip: 8
},
//请求头信息
headers:{
h: 416,
w: 416,
c: 3
}
}).then(value => {
console.log(value);
});
}
btns[2].onclick = function(){
// 通用方式
axios({
//请求方法
method: "POST",
//url
url: '/axios-server',
// url参数
params:{
vip: 1,
level: 30
},
//头信息
headers:{
a:100,
b:200
},
//请求体参数
data:{
user:"m_ad",
pwd:123
}
}).then(response => {
console.log(response);
})
}
</script>
</html>
fetch()
创建只有一个按钮的html网页包含如下script脚本:
const btn = document.querySelector('button')
btn.onclick = function(){
fetch('http:127.0.0.1:8000/fetch-server', {
//请求方法
method:"POST",
//请求头
headers:{
name:"moonjay",
age:23
},
//请求体
body: 'username=admin&pwd=123'
}).then(response => {
console.log(response);
// or return response.json();
}) // 返回类型为 promise
}
server.js
文件修改同上
跨域
Ajax默认遵守同源策略
首先介绍一下同源与跨域:
- 同源策略(Same-Origin Policy)最早由Netscape公司提出,是浏览器的一种安全策略
- 同源: 协议、域名、端口号必须完全相同
- 跨域: 违背同源策略就是跨域
如何解决跨域
- JSONP
- CORS
JSONP
什么是JSONP
Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
为什么我们从不同的域(网站)访问数据需要一个特殊的技术( JSONP )呢?这是因为同源策略。
由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
在网页有一些标签天生具有跨域能力,比如:img link iframe script。
JSONP 就是利用script标签的跨域能力来发送请求的。只支持GET请求
原理展示
新建HTML页面JSONP_Ajax.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONP原理</title>
</head>
<body>
<script src="./js/app.js"></script>
</body>
</html>
同级目录下,新建js/app.js
:
const data = {
name: "moonjay"
};
console.log(data)
运行程序,访问HTML页面(直接打开.html
文件,使用的是file协议)即可在控制台看到输出。
借助VS Code的插件–Live Server打开
.html
文件,使用的是HTTP协议,访问的是127.0.0.1:port/HTML文件路径
。此时,<script src="127.0.0.1:port/js文件路径"></script>
JSONP的使用
JSONP_Ajax.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSONP原理</title>
<style>
#result{
width: 300px;
height: 100px;
border: solid 1px #78a;
}
</style>
</head>
<body>
<div id="result"></div>
用户名:<input type="text" id="username">
<p></p>
<script>
const result = document.getElementById('result');
const input = document.querySelector('input');
const p = document.querySelector('p');
// 声明 handle 函数
function handle1(data){
// div填充
result.innerHTML = data.name;
}
function handle2(data){
// 输入框 和 p标签文本
input.style.border = "solid 1px #f00";
p.innerHTML = data.msg;
}
//绑定事件
input.onblur = function(){
//获取用户输入值
let username = this.value;
// 1.创建 script 标签
const script = document.createElement('script');
// 2.设置标签的 src
script.src = 'http://127.0.0.1:8000/check_username'
// 3.将 script标签插入文档中
document.body.appendChild(script);
}
</script>
<!--script脚本链接放最后 不然出现handle未定义-->
<!-- <script src="./js/app.js"></script> -->
<script src="http://127.0.0.1:8000/jsonp-server"></script>
</body>
</html>
在server.js
中加入代码:
// jsonp_ajax.html文件用 -- 1
app.all('/jsonp-server', (request, response) => {
// response.send("console.log('hello jsonp')"); //传递脚本
const data = {
name: "moonjay jsonp",
};
let str = JSON.stringify(data);
response.send(`handle1(${str})`);
});
// jsonp_ajax.html文件用 -- 2
app.all('/check_username', (request, response) => {
const data = {
exist: 1,
msg: '用户名已存在'
};
let str = JSON.stringify(data);
response.send(`handle2(${str})`);
});
jQuery中的JSONP
参数 callback 是固定写法
server.js
:
控制台查看callback参数:
HTML文档:
CORS
文档链接:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
CORS 是什么?
CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get 和post 请求。跨域资源共享标准新增了一组HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。
CORS 怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
CORS 的使用
主要是服务器端的设置:
router.get("/testAJAX" , function (req , res) {
//通过res 来设置响应头,来允许跨域请求,不然会报CORS错误
//res.set("Access-Control-Allow-Origin","http://127.0.0.1:3000");
res.set("Access-Control-Allow-Origin","*");
res.send("testAJAX 返回的响应");
});