- ***当前阶段的笔记 ***
「面向实习生阶段」https://www.aliyundrive.com/s/VTME123M4T9 提取码: 8s6v
点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。
文章目录
- 一、Ajax简介
- 二、原生Ajax
- 三、常见三种Ajax请求方式
- 四、跨域与解决
- 1、jsonP
- 2、CORS
- Ⅰ-代码示例
- Ⅱ-[HTTP 响应首部字段](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#http_响应首部字段)
- 1、[Access-Control-Allow-Origin](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#access-control-allow-origin)
- 2、[Access-Control-Expose-Headers](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#access-control-expose-headers)
- 3、[Access-Control-Max-Age](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#access-control-max-age)
- 4、[Access-Control-Allow-Credentials](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#access-control-allow-credentials)
- 5、[Access-Control-Allow-Methods](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#access-control-allow-methods)
- 6、[Access-Control-Allow-Headers](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#access-control-allow-headers)
- Ⅲ-[HTTP 请求首部字段](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#http_请求首部字段)
- 1、[Origin](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#origin)
- 2、[Access-Control-Request-Method](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#access-control-request-method)
- 3、[Access-Control-Request-Headers](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS#access-control-request-headers)
- 五、服务端代码示例
一、Ajax简介
AJAX 简介 AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
1、XML简介
XML 可扩展标记语言。
XML 被设计用来传输和存储数据。
XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签, 全都是自定义标签,用来表示一些数据。
比如说我有一个学生数据:
name = “孙悟空” ; age = 18 ; gender = “男” ;
用 XML 表示:
<student>
<name>孙悟空</name>
<age>18</age>
<gender>男</gender>
</student>
现在已经被 JSON 取代了。
{"name":"孙悟空","age":18,"gender":"男"}
2、Ajax的特点
Ⅰ-AJAX 的优点
可以无需刷新页面而与服务器端进行通信。
允许你根据用户事件来更新部分页面内容。
Ⅱ-Ajax的缺点
没有浏览历史,不能回退
存在跨域问题(同源)
SEO 不友好
3、HTTP简介
HTTP(hypertext transport protocol)协议『超文本传输协议』,协议详细规定了浏览器和万维网服务器之间互相通信的规则、约定,、规则
Ⅰ-请求报文
重点是格式与参数
行 POST /s?ie=utf-8 HTTP/1.1 头 Host: atguigu.com Cookie: name=guigu Content-type: application/x-www-form-urlencoded User-Agent: chrome 83 空行 体 username=admin&password=admin
Ⅱ-响应报文
行 HTTP/1.1 200 OK 头 Content-Type: text/html;charset=utf-8 Content-length: 2048 Content-encoding: gzip 空行 体 <html> <head> </head> <body> <h1>尚硅谷</h1> </body> </html>
Ⅲ-Chrome网络控制台查看通信报文
1、Network --> Hearders 请求头
2、Network --> Response 响应体:通常返回的是html
Ⅳ-http协议概述
http协议全称超文本传输协议,大家只要把它理解成为一个服务器与客户端通信的协议即可。
在http协议的约定下,客户端可以向服务器发送请求,服务器在接收到请求之后,给予客户端响应。
Ⅴ-http协议请求的常用方法
本节我们讲解http协议常用的四种方法,用来完成数据的增、删、改、查操作。
- get方法:获取数据
- post方法:提交数据
- put方法:修改数据
- delete方法:删除数据
对于初学者,这里需要注意的是,http请求本身并不会完成增删改查的基本操作,真正的操作仍然是由服务器完成。
这些操作仅仅是一种约定,例如:我们用get请求配合服务器程序,可以获取数据,同样也可以添加、删除、修改数据,但是为了规范我们的程序,通常只用get方法来查询数据。
Ⅵ-http协议状态码
http的状态码被分为5大类,状态码为客户端提供一种理解事务处理结果的便捷方式,我们在network工具中可以看到响应头中的的状态码。
- 100~199(信息性状态码):HTTP/1.1向协议中引入了信息性状态码
- 200~299(成功状态码):客户端发起请求时,这些请求通常都是成功的。服务器有一组用来表示成功的状态码,分别对应于不同类型的请求
- 300~399(重定向状态码):重定向状态码要么告知客户端使用替代位置来访问他们所感兴趣的资源,要么就提供一个替代的响应而不是资源的内容
- 400~499(客户端状态码):有时客户端会发送一些服务器无法处理的东西。浏览网页时,我们都看到过臭名昭著的404 Not Found错误码,这只是服务器在告诉我们,它对我们请求的资源一无所知
- 500~599(服务器状态码):有时客户端发送了一条有效请求,服务器自身却出错了,这些会返回5xx状态码
下面三个常用的HTTP状态码使我们必须要记住的:
- 200 OK:请求被正常处理
- 404 Not Found:服务器找不到客户端请求的资源,也有可能是服务器不想让你访问而故意返回404
- 500 Internal Server Error:服务器内部错误
Ⅶ-Postman 增删改查
数组的splice可以实现数组元素的添加、删除、和修改。用法如下:
let dataList = ["香蕉","苹果","鸭梨"];
dataList.splice(0,1) //从索引为0的元素开始,删除1个元素,此案例会删除香蕉-删除功能。
dataList.splice(1,0,"草莓") //从索引为1的元素开始,删除0个元素,并在删除元素的位置插入"草莓"-添加功能。
dataList.splice(1,1,"草莓") //从索引为1的元素开始,删除1个元素,并在删除元素的位置插入"草莓"-修改功能。
server.js服务器编码:
// get查看(获取)
router.get("/fruits", ctx => {
ctx.body = dataList //直接返回数组
})
// post添加
router.post("/fruits", ctx => {
let fruit = ctx.request.body.fruit
dataList.push(fruit) // .push()方法可以在数组结尾追加数据
ctx.body = dataList // 数据是存储在服务器的内存里,重启服务器则清空
})
//put修改
router.put("/fruits/:id", ctx => {
// 路由传参 /:id --> ctx.params.id 可以获取id
let id = ctx.params.id
let fruit = ctx.request.body.fruit
dataList.splice(id,1,fruit)
// splice(startIndex, deleteCount, replaceItem)
ctx.body = dataList
})
//delete删除
router.delete("/fruits/:id", ctx => {
let id = ctx.params.id
dataList.splice(id,1)
ctx.body = dataList
})
4、安装nodemon自动重启工具
二、原生Ajax
1、XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的。
2、当你前端想设置自定义的请求头时,需要如此后端设置响应头
//表示接收任意类型的请求 app.all('/server', (request, response) => { //响应头 允许跨域 运行自定义响应头 response.setHeader('Access-Control-Allow-Origin', '*'); response.setHeader('Access-Control-Allow-Headers', '*'); }
3、
ajax请求状态
:xhr.readyState
0:请求未初始化,还没有调用 open()。 1:请求已经建立,但是还没有发送,还没有调用 send()。
2:请求已发送,正在处理中(通常现在可以从响应中获取内容头)。
3:请求在处理中;通常响应中已有部分数据可用了,没有全部完成。
4:响应已完成;您可以获取并使用服务器的响应了
〇-Ajax的使用
使用步骤:
1) 创建 XMLHttpRequest 对象 var xhr = new XMLHttpRequest(); 2) 设置请求信息 xhr.open(method, url); //可以设置请求头,一般不设置 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 3) 发送请求 xhr.send(body) //get 请求不传 body 参数,只有 post 请求使用 4) 接收响应 //xhr.responseXML 接收 xml 格式的响应数据 //xhr.responseText 接收文本格式的响应数据 xhr.onreadystatechange = function (){ if(xhr.readyState == 4 && xhr.status == 200){ var text = xhr.responseText; console.log(text); }}
Ⅰ-Get方式
<script>
var div = document.querySelector('div')
var btn = document.querySelector('button')
btn.addEventListener('click', () => {
var xhr = new XMLHttpRequest()
// xhr.open('get', 'http://127.0.0.1:3000/server')
//get() 传输数据放入open()中
xhr.open('get', 'http://127.0.0.1:3000/server?a=100&b=200&c=300');
xhr.send()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
console.log(xhr.status)// 状态码
console.log(xhr.statusText)// 状态字符串
console.log(xhr.getAllResponseHeaders())// 所有请求头
console.log(xhr.response)// 请求体
div.innerHTML = xhr.response
}
}
}
})
</script>
Ⅱ-json数据请求
<script>
var div = document.querySelector('div')
div.addEventListener('click', function () {
var xhr = new XMLHttpRequest();
// *2*.(自动转换) 设置响应体数据的类型
xhr.responseType = 'json';
xhr.open('get', 'http://127.0.0.1:3000/json-server');
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
// 1.手动转换
// var data = JSON.parse(xhr.response)
// console.log(data);
// div.innerHTML = data.name;
// 2.自动转换
div.innerHTML = xhr.response.name;
}
}
}
})
</script>
Ⅲ-Post方式
Post需要请求头
<script>
var div = document.querySelector('div')
var btn = document.querySelector('button')
btn.addEventListener('click', () => {
var xhr = new XMLHttpRequest()
xhr.open('post', 'http://127.0.0.1:3000/server')
// 必须设置请求头
// Content—Type设置请求体内容的类型 参数2:send()方法中查询字符串的类型,为固定模式
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 在请求头中加入自定义信息
xhr.setRequestHeader('name', 'text')
// Post传输数据放入send()中, 而get放入open()中
// xhr.send()
xhr.send("username=xxx&pwd=123");
// xhr.send("username:xxx&pwd:123");
// xhr.send("asdfghjk");
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
div.innerHTML = xhr.response
}
}
}
})
</script>
Ⅳ-解决ie缓存问题
问题:在一些浏览器中(IE),由于
缓存机制
的存在,ajax 只会发送的第一次请求,剩余多次请求不会再发送给浏览器而是直接加载缓存中的数据。解决方式:浏览器的缓存是根据 url地址来记录的,所以我们只需要修改 url 地址 即可避免缓存问题
xhr.open("get","/testAJAX?t="+Date.now());
<script>
const btn = document.getElementsByTagName('button')[0]
const result = document.getElementById('result')
btn.addEventListener('click', function () {
const xhr = new XMLHttpRequest()
xhr.open("get", 'http://127.0.0.1:3000/ie?t=' + Date.now())
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response);
result.innerHTML = xhr.response
}
}
}
})
</script>
Ⅴ-请求超时与网络异常
当你的请求时间过长,或者无网络时,进行的相应处理
<script>
var div = document.querySelector('div')
div.addEventListener('click', function () {
var xhr = new XMLHttpRequest();
xhr.timeout = 2000;
xhr.ontimeout = function () {
console.log('超时异常');// 定时器时间小于当前设置时间
}
xhr.onerror = function () {
console.log('网络异常');
}
xhr.open('get', 'http://127.0.0.1:3000/delay');
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
div.innerHTML = xhr.response
}
}
}
})
</script>
Ⅵ-取消请求
在请求发出去后
但是未响应完成
时可以进行取消请求操作
<script>
var btns = document.querySelectorAll('button')
var x = null
var isSending = false;
btns[0].addEventListener('click', () => {
console.log("isSending", isSending); // false
if (isSending) {
x.abort()
this.disabled = false;
}
x = new XMLHttpRequest();
isSending = true
btns[0].disabled = true
x.open('get', 'http://127.0.0.1:3000/delay')
x.send()
console.log("isSending", isSending);
x.onreadystatechange = () => {
if (x.readyState === 4) {
if (x.status >= 200 && x.status <= 300) {
isSending = false
btns[0].disabled = isSending
console.log("isSending", isSending);
}
}
}
})
btns[1].addEventListener('click', () => {
x.abort()
})
</script>
Ⅶ-重复请求问题
利用之前Ⅴ中取消请求知识点,当我点击时判断之前请求是否在发送中,如果是,则停止请求
<script>
const btns = document.querySelectorAll('button')
let x = null
let isSending = false; // 是否正在发送AJAX请求
btns[0].onclick = function () {
if (isSending) {
x.abort()
}
// ↑ 如果正在发送,则取消该请求,创建一个新的请求
x = new XMLHttpRequest()
isSending = true // 修改标识变量的值
x.open('GET', 'http://127.0.0.1:3000/delay')
x.send()
x.onreadystatechange = function () {
if (x.readyState === 4) {
isSending = false
}
}
}
</script>
三、常见三种Ajax请求方式
1、jQuery发送AJAX请求
jQuery有三种发送请求方法:
当你只是简单的请求数据,可以直接使用前两种方式请求,当你需要设置的东西较多的时候,可以使用
$.ajax()
方法
Ⅰ-$.get()
$("button").eq(0).click(() => {
$.get('http://127.0.0.1:3000/jquery-server', {a: 100, b: 200}, (data) => {
console.log(data)
}, 'json')
})
Ⅱ-$.post()
$("button").eq(1).click(() => {
$.post('http://127.0.0.1:3000/jquery-server', {a: 100, b: 200}, (data) => {
console.log(data)
}, 'json')
})
Ⅲ-$.ajax
$("button").eq(2).click(() => {
$.ajax({
url: 'http://127.0.0.1:3000/jquery-server',
data: {c: 300, d: 400},
type: 'get',
dataType: 'json',
success: (data) => {
console.log(data)
},
error: (error) => {
console.log(error)
},
timeout: 2000,
headers: {
e: 500,
f: 600
}
})
})
2、Axios发送AJAX请求
Ⅰ-axios.get()
axios.defaults.baseURL = 'http://127.0.0.1:3000'
axios.get(url,data,params)
axios.defaults.baseURL = 'http://127.0.0.1:3000'
btns[0].addEventListener('click', () => {
axios.get('/axios-server', {
params: {
id: 'mc',
name: "machao"
},
headers: {
name: 'xxx',
age: 20
}
}).then((value) => {
console.log(value)
console.log(value.data)
}).catch((value) => {
console.log(value)
})
})
Ⅱ-axios.post()
axios.post(url,data,params)
btns[1].addEventListener('click', () => {
axios.post('/axios-server', {
params: {
id: 'mc',
name: "machao"
},
headers: {
name: 'xxx',
age: 20
}
}).then((value) => {
console.log(value)
console.log(value.data)
}).catch((value) => {
console.log(value)
})
})
Ⅲ-axios() 常用
axios({})
btns[2].addEventListener('click', () => {
axios({
method: 'get',
url: '/axios-server',
params: {
id: 'mc',
name: "machao"
},
headers: {
name: 'xxx',
age: 20
}
}).then((response) => {
console.log(response.status)
console.log(response.statusText)
console.log(response.headers)
console.log(response.data)
}).catch((e) => {
console.log(e)
})
3、Fetch发送AJAX请求
<script>
const btn = document.querySelector('button')
btn.onclick = async () => {
//优化后:
try {
const response = await fetch('http://127.0.0.1:3000/fetch-server?vip=10')
const data = await response.json()
console.log(data);
} catch (error) {
console.log('请求出错', error);
}
}
const btn = document.querySelector('button')
btn.addEventListener('click', () => {
fetch('http://127.0.0.1:3000/fetch-server?a=100', {
method: 'post',// get 设置不了请求体,把body注释掉了就可以用get了
headers: {
name: 'admin'
},
body: 'username=admin&password=123'
}).then(response => {
console.log(response)
return response.json()
}).then(response => {
console.log(response)
}).catch(
(error) => {
console.log(error)
}
)
})
</script>
四、跨域与解决
1、什么是跨越?
- 一个网页向另一个不同域名/不同协议/不同端口的网页请求资源,这就是跨域。
- 跨域原因产生:在当前域名请求网站中,默认不允许通过ajax请求发送其他域名。
2、为什么会产生跨域请求?
- 因为浏览器使用了同源策略
3、什么是同源策略?
- 同源策略是Netscape提出的一个著名的安全策略,现在所有支持JavaScript的浏览器都会使用这个策略。同源策略是浏览器最核心也最基本的安全功能,如果缺少同源策略,浏览器的正常功能可能受到影响。可以说web是构建在同源策略的基础之上的,浏览器只是针对同源策略的一种实现。
- 同源: 协议、域名、端口号 必须完全相同。 违背同源策略就是跨域。
4、为什么浏览器要使用同源策略?
是为了保证用户的信息安全,防止恶意网站窃取数据,如果网页之间不满足同源要求,将不能:
1、共享Cookie、LocalStorage、IndexDB
2、获取DOM
3、AJAX请求不能发送
5、跨域的五个解决方式:
1、前端使用jsonp (不推荐使用)
2、后台Http请求转发
3、后台配置同源Cors (推荐)
4、使用SpringCloud网关
5、使用nginx做转发 (推荐)
本课程提到了其中的两种:
1、jsonP
1)JSONP 是什么?
JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明 才智开发出来,只支持 get 请求。
2)JSONP 怎么工作的?
在网页有一些标签天生具有跨域能力,比如:img link iframe script。 JSONP 就是利用 script 标签的跨域能力来发送请求的。
Ⅰ-jsonP的使用
// 1. 动态的创建一个 script 标签------------------------------------------------------------
var script = document.createElement("script");
//2. 设置 script 的 src, 设置回调函数
script.src = "http://localhost:3000/jsonp-server";
function fn(data) {
alert(data.name);
};
// 3. 将 script 添加到 body 中
document.body.appendChild(script);
// 4. 服务器中路由的处理------------------------------------------------------
app.all('/jsonp-server', (request, response) => {
// response.send('console.log("hello jsonp")');
const data = {name: 'machao'};
//将数据转化为字符串
let str = JSON.stringify(data);
//返回结果
response.send(`fn(${str})`);
// response.end(`fn(${str})`);
});
Ⅱ-jQuery发送jsonP请求
//前端代码-----------------------------------------------------------------------------------
$('button').eq(0).click(function () {
$.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function (data) {
$('#result').html(`
名称: ${data.name}<br>
校区: ${data.city}
`)
});
});
//服务端代码-----------------------------------------------------------
app.all('/jquery-jsonp-server', (request, response) => {
// response.send('console.log("hello jsonp")');
const data = {
name: '尚硅谷',
city: ['北京', '上海', '深圳']
};
//将数据转化为字符串
let str = JSON.stringify(data);
//接收 callback 参数
let cb = request.query.callback;
//返回结果
response.end(`${cb}(${str})`);
});
Ⅲ-我自己开发封装的jsonP插件
1、代价:需要前后端联动
2、精髓:自动的由插件生成方法名,并在当前的页面动态的生成函数,然后再生成的函数里头调用用户预留的回调函数
3、插件:自动化的去模拟基于script去实现跨域请求的过程(对用户来说是黑盒子)
4、参数拼接:url已经是带参的。和不带参的
5、id优化 额可以添加一个容器来管理id
1、前端调用测试封装好的jsonP代码
//测试调用函数 let test=function () { jsonP.req({ url:"http://localhost:3000/jsonpx", data:{ a:"111" }, callback:function (result) { alert("成功"+result) } }) }
2、服务端测试代码
router.get('/jsonpx', async function (req, resp, next) { let callback=req.query.callback; let data=req.query.a; if (!data){ resp.send(`${callback}('洪jl:我是服务端代码')`) } resp.send(`${callback}('洪jl:我是服务端代码`+data+`')`)})
3、封装原生代码
<script> /**author:@hongjilin * 1.声明一个jsonP插件对象 * 作用:隔开作用域 */ let jsonP = {}; /** *2.在插件对象中创建两个名字备用符数组 */ jsonP.char = { Number: '0123456789', Letter: 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM' } /** * 通过随机数抽取备用字符数组库拼凑函数id * @param charLen * @param numLen */ jsonP.newFunId = function (charLen, numLen) { let id = ''; for (let i = 0; i < charLen; i++) { id += this.char.Letter.charAt(Math.random() * 52) } for (let j = 0; j < numLen; j++) { id += Math.floor(Math.random() * 10); } return id; } /** * 拼接路径 * @param url * @param key * @param value */ jsonP.jointUrl = function (url, key, value) { if (url && key && value) { let sign = "&" //如果是第一次 if (url.indexOf('?') == -1) { sign = '?' } url += sign + key + "=" + value } return url; } /** 封装err属性方便 */ jsonP.err = function (msg) { console.error(msg) } /** * 发送请求函数 * @param options */ jsonP.req = function (options) { let jsonId={}; //1.生成方法名 jsonId.funId = this.newFunId(4,8); let Userurl = options.url; let Userdata = options.data; if (!options) { this.err("输入不能空") return; } else if (!Userurl) { this.err("url不能空") return; } else if (!Userdata) { //如果没有data,初始化 Userdata = {}; } //将函数名赋值给userdata的回调函数属性中 Userdata.callback = jsonId.funId; for (let key in Userdata) { Userurl = this.jointUrl(Userurl, key, Userdata[key]) } let script = document.createElement('script'); script.setAttribute("id" , jsonId.funId); script.setAttribute("src" , Userurl); //动态生成函数 let callback=function (result) { console.log("xxxxxxx") //业务逻辑回调 if (options.callback){ try { options.callback(result) }catch (e) { this.err(e.message) } } //善后 let tmp=document.getElementById(jsonId.funId) tmp.parentNode.removeChild(tmp); eval(jsonId.funId+'=null') } eval("window."+jsonId.funId+"=function(result){ callback(result) }") document.head.appendChild(script) }</script>
2、CORS
1、CORS文档链接
2、CORS是什么?
CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方 案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些 源站通过浏览器有权限访问哪些资源
3、CORS是怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应 以后就会对响应放行。
Ⅰ-代码示例
app.all('/cors-server', (request, response) => {
//设置响应头
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", '*');
response.setHeader("Access-Control-Allow-Method", '*');
// response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
response.send('Hello CORS!');
});
Ⅱ-HTTP 响应首部字段
本节列出了规范所定义的响应首部字段。上一小节中,我们已经看到了这些首部字段在实际场景中是如何工作的。
1、Access-Control-Allow-Origin
响应首部中可以携带一个
Access-Control-Allow-Origin
字段,其语法如下:Access-Control-Allow-Origin: <origin> | *
其中,origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。
例如,下面的字段值将允许来自 http://mozilla.com 的请求:
Access-Control-Allow-Origin: http://mozilla.com
如果服务端指定了具体的域名而非“*”,那么响应首部中的 Vary 字段的值必须包含 Origin。这将告诉客户端:服务器对不同的源站返回不同的内容。
2、Access-Control-Expose-Headers
译者注:在跨源访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。
Access-Control-Expose-Headers
头让服务器把允许浏览器访问的头放入白名单,例如:Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
这样浏览器就能够通过getResponseHeader访问
X-My-Custom-Header
和X-Another-Custom-Header
响应头了。
3、Access-Control-Max-Age
Access-Control-Max-Age
头指定了preflight请求的结果能够被缓存多久,请参考本文在前面提到的preflight例子。Access-Control-Max-Age: <delta-seconds>
delta-seconds
参数表示preflight请求的结果在多少秒内有效。
4、Access-Control-Allow-Credentials
Access-Control-Allow-Credentials
头指定了当浏览器的credentials
设置为true时是否允许浏览器读取response的内容。当用在对preflight预检测请求的响应中时,它指定了实际的请求是否可以使用credentials
。请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。Access-Control-Allow-Credentials: true
5、Access-Control-Allow-Methods
Access-Control-Allow-Methods
首部字段用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。Access-Control-Allow-Methods: <method>[, <method>]*
6、Access-Control-Allow-Headers
Access-Control-Allow-Headers
首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。Access-Control-Allow-Headers: <field-name>[, <field-name>]*
Ⅲ-HTTP 请求首部字段
本节列出了可用于发起跨源请求的首部字段。请注意,这些首部字段无须手动设置。 当开发者使用 XMLHttpRequest 对象发起跨源请求时,它们已经被设置就绪。
1、Origin
Origin
首部字段表明预检请求或实际请求的源站。Origin: <origin>
origin 参数的值为源站 URI。它不包含任何路径信息,只是服务器名称。
Note: 有时候将该字段的值设置为空字符串是有用的,例如,当源站是一个 data URL 时。
注意,在所有访问控制请求(Access control request)中,
Origin
首部字段总是被发送
2、Access-Control-Request-Method
Access-Control-Request-Method
首部字段用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。Access-Control-Request-Method: <method>
3、Access-Control-Request-Headers
Access-Control-Request-Headers
首部字段用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。Access-Control-Request-Headers: <field-name>[, <field-name>]*
五、服务端代码示例
配合以上前端代码的服务端代码
//cd C:\Users\mc952190617\Desktop\马超\布卡\work\Ajax
// 1. 引入express
const {request, response} = require('express');
const express = require('express');
// 2. 创建应用对象
const app = express();
// 3. 创建路由规则
app.get('/server', (request, response) => {
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应体
response.send("Hello get");
});
// app.post('/server', (request, response) => {
// // 设置响应头, 设置允许跨域
// response.setHeader('Access-Control-Allow-Origin', '*');
// // 设置响应体
// response.send("Hello Ajax post");
// });
app.all('/server', (request, response) => {
// 设置响应头, 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置自定义响应头,然后POST改为all接受任意请求
response.setHeader('Access-Control-Allow-Headers', '*');
// 设置响应体
response.send("Hello Ajax all");
});
app.get('/ie', (request, response) => {
//设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
//设置响应体
response.send('HELLO IE - 5');
});
app.all('/json-server', (request, response) => {
// 设置响应头, 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应头, 设置允许自定义头信息
response.setHeader('Access-Control-Allow-Headers', '*');
// 响应一个数据
const data = {
name: 'asdf'
};
// 对对象进行字符串转换
let str = JSON.stringify(data)
// 设置响应体
response.send(str);
});
app.all('/delay', (request, response) => {
// 设置响应头, 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置自定义响应头,然后POST改为all接受任意请求
response.setHeader('Access-Control-Allow-Headers', '*');
// 设置响应体
setTimeout(function () {
response.send('延迟响应') // 定时器时间大于设置时间输出当前内容
}, 3000)
});
app.all('/jquery-server', (request, response) => {
// 设置响应头, 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置自定义响应头,然后POST改为all接受任意请求
response.setHeader('Access-Control-Allow-Headers', '*');
// 设置响应体
var data = {
name: 'machao'
}
response.send(JSON.stringify(data))
});
app.all('/axios-server', (request, response) => {
// 设置响应头, 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置自定义响应头,然后POST改为all接受任意请求
response.setHeader('Access-Control-Allow-Headers', '*');
// 设置响应体
var data = {
name: '马超'
}
response.send(JSON.stringify(data))
});
app.all('/fetch-server', (request, response) => {
// 设置响应头, 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 设置自定义响应头,然后POST改为all接受任意请求
response.setHeader('Access-Control-Allow-Headers', '*');
// 设置响应体
var data = {
name: 'fetch'
}
response.send(JSON.stringify(data))
});
//jsonp服务
app.all('/jsonp-server', (request, response) => {
// response.send('console.log("hello jsonp")');
const data = {name: '尚硅谷atguigu'};
//将数据转化为字符串
let str = JSON.stringify(data);
//返回结果
response.end(`handle(${str})`);
});
//用户名检测是否存在
app.all('/check-username', (request, response) => {
// response.send('console.log("hello jsonp")');
const data = {exist: 1, msg: '用户名已经存在'};
//将数据转化为字符串
let str = JSON.stringify(data);
//返回结果
response.end(`handle(${str})`);
});
app.all('/jquery-jsonp-server', (request, response) => {
// response.send('console.log("hello jsonp")');
const data = {name: '尚硅谷', city: ['北京', '上海', '深圳']};
//将数据转化为字符串
let str = JSON.stringify(data);
//接收 callback 参数
let cb = request.query.callback;
//返回结果
response.end(`${cb}(${str})`);
});
app.all('/cors-server', (request, response) => {
//设置响应头
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", '*');
response.setHeader("Access-Control-Allow-Method", '*');
// response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
response.send('hello CORS');
});
// 4. 监听服务
app.listen(3000, () => {
console.log("服务已经启动, 3000 端口监听中...");
})
// response.send('console.log("hello jsonp")');
const data = {exist: 1, msg: '用户名已经存在'};
//将数据转化为字符串
let str = JSON.stringify(data);
//返回结果
response.end(`handle(${str})`);
});
app.all('/jquery-jsonp-server', (request, response) => {
// response.send('console.log("hello jsonp")');
const data = {name: '尚硅谷', city: ['北京', '上海', '深圳']};
//将数据转化为字符串
let str = JSON.stringify(data);
//接收 callback 参数
let cb = request.query.callback;
//返回结果
response.end(`${cb}(${str})`);
});
app.all('/cors-server', (request, response) => {
//设置响应头
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", '*');
response.setHeader("Access-Control-Allow-Method", '*');
// response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
response.send('hello CORS');
});
// 4. 监听服务
app.listen(3000, () => {
console.log("服务已经启动, 3000 端口监听中...");
})