AJAX请求跨域问题
ajax不是js的规范,其全名为Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求。当使用AJAX技术向不同源(协议、域名或端口)的服务器发起请求时,浏览器出于安全考虑会阻止这种请求,这就是所谓的跨域问题。本文将对ajax、同源策略、以及CORS原理进行探讨。
ajax有什么作用
1、ajax的概念与作用
使用传统的form表单时,当点击submit按钮后表单开始提交,这时浏览器会刷新页面,新的页面中会显示成功或失败的信息。若网络出现问题则会显示404页面。也就是说每一次的请求对应一个页面,每次请求都会刷新页面
但在一些情况下需要发送http请求,但是不希望页面刷新,ajax便很好的解决了这个需求。
AJAX(Asynchronous JavaScript and XML)它允许网页在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页内容。
优点:无需刷新整个页面即可更新内容;只传输必要数据而非整个页面
2、ajax的实现
ajax核心是通过XMLHttpRequest对象
或Fetch API
与服务器进行异步通信
XMLHttpRequest
js
// XMLHttpRequest
const xhr = new XMLHttpRequest()
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send();
Fetch API
Fetch API配合async写法,代码更加简单。
js
const getData = async (url)=> {
const res = await fetch(url)
const result = await res.json()
return result
}
const data = getData('./content.html')
3、跨域问题
-
同源策略
假设当前页面URL是
https://example.com/path/to/page.html
,那么./content.html
会解析为https://example.com/path/to/content.html
,这是因为浏览器的同源策略导致的。同源是指默认情况下JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致(只能访问与当前页面同源的资源)。即协议、域名、端口都要相同同源策略是浏览器的安全机制,它会限制不同源的DOM访问、不同源的AJAX请求、不同源的Cookie、LocalStorage等访问。但对于标签元素的限制比较小。
例如:当你登录了
bank.com
,并保留了会话 Cookie,然后你访问了一个恶意网站evil.com
,它偷偷向bank.com
发起 AJAX 请求(跨域请求) 。由于浏览器会自动带上bank.com
的 Cookie,evil.com
就能窃取你的银行数据,甚至进行转账操作。而同源策略阻止了这种攻击,确保只有bank.com
自己的页面才能访问bank.com
的数据。若发送请求的URL地址为
https://www.sina.com.cn/
,这是一个不同源的ajax请求,会报错:同源策略的实现逻辑:
浏览器会先正常发送请求到服务器(请求中携带Origin:
https://www.sina.com.cn/
头)------>服务器会处理请求并返回响应------>浏览器检查请求是否同源若,不同同源浏览器才会拦截响应,不把响应数据交给前端代码关键点 :跨域限制不是阻止请求发送,而是阻止前端JavaScript代码访问响应。服务器始终会收到请求并返回响应,只是浏览器会根据响应头决定是否让前端代码看到这个响应。
-
CORS解决跨域
COTS是一套允许跨域访问的规则 ,通过 HTTP 头实现。它是通过服务器来告诉浏览器:"我允许某些来源的请求"。也就是说CORS是依赖于服务器的,前端页面是解决不了的。只要服务器明确表示允许,则校验通过,若服务器拒绝或没有明确表示,则不通过。
实现流程
-
浏览器 发送跨域请求(如
fetch("https://api.example.com/data")
) -
服务器 返回响应,并带上 CORS 头:
httpAccess-Control-Allow-Origin: https://api.example.com/data Access-Control-Allow-Methods: GET, POST
-
浏览器 检查响应头,如果
Access-Control-Allow-Origin
匹配当前域名或者为***** (代表允许所有访问),就允许前端代码读取响应,否则报跨域错误。
CORS将请求分为两类:简单请求、预检请求,不是简单请求的就是预检请求
简单请求
请求方法为:GET、HEAD、POST;
头部字段满足CORS安全规范(不改动请求头部)
请求头的Content-Type为:text/plain、 multipart/form-data、application/x-www-form-urlencoded
js// 简单请求 fetch('https://www.baidu.com/') // 预检请求 改动了请求头 fetch('https://www.baidu.com/', { method: 'POST', headers: { name:'s' }, }) // 预检请求 fetch('https://www.baidu.com/', { method: 'POST', headers: { 'Content-Type': 'application/json' // 改动了Content-Type }, body: JSON.stringify({ name: '张三', age: 18 }) })
简单请求于预检请求发送方式的区别
简单请求
-
浏览器直接发送请求(不带预检 ),自动添加
Origin
头。 -
服务器返回响应,需包含:
httpAccess-Control-Allow-Origin: * 或当前域名
-
浏览器检查响应头:若合法则返回数据给前端,若非法则拦截响应(但请求已到达服务器)。
预检请求prefight
-
浏览器先发送
OPTIONS
预检请求,携带:httpOrigin: https://my.com Access-Control-Request-Method: PUT // 声明真实请求方法 Access-Control-Request-Headers: X-API-Key // 声明自定义头
-
服务器需响应预检,返回:
httpAccess-Control-Allow-Origin: 允许的源 Access-Control-Allow-Methods: GET, POST, PUT // 允许的方法 Access-Control-Allow-Headers: X-API-Key // 允许的头 Access-Control-Max-Age: 86400 // 预检缓存时间(秒)
-
浏览器检查预检响应,若符合要求则 发送真实请求,若不符合则阻止真实请求(控制台报错)
-