网络-深入浅出篇文章:
一. AJAX
ajax的诞生:
- 发送网络请求的方式:
- 在浏览器中直接输入网址 (其无法用代码控制)
- 在控制台输入location.href="url" ,可以发送网络请求,但是页面会发生跳转(页面会跳转)
- 带有src属性的标签 —— 例如img ,请求是可以发出的,服务端是可以处理的并且也是可以返回的,但是返回后,能否被应用,还要看浏览器(页面无法处理返回结果)
- 带有href属性的标签 —— 例如link ,请求是可以发出的,服务端是可以处理的也是可以返回的,但是返回后,能否被应用,还要看浏览器(页面无法处理返回结果)
- 带有action属性的标签 例如form表单,也可以向后端发出请求,但form表单发送请求后也会页面跳转(页面会跳转)
- ajax诞生:
- 就是因为希望有一种方式,既可以用代码控制,而且页面不会跳转,并且服务端返回的结果我们可以用JS继续处理,所以就有了ajax
ajax的应用:
-
ajax 全名: async javascript and xml
-
ajax 的请求要素:
- 请求方式: Get/Post
- url
- 但ajax受到浏览器同源策略的限制,同源策略是浏览器提出的一种安全机制
- 发送请求-兼容写法:
例:
var xhr = null
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest() //常用浏览器自带
} else {
xhr = new ActiveXObject("Microsoft.XMLHttp") //IE6自带
}
xhr.open("get", "http://www.baidu.com", true) // 第三个参数 true 代表异步
xhr.send() //这就可以发送了 但有可能有跨域问题,把xhr.send放在xhr.onreadystatechange后比较好
3. 原生js发送ajax
例:
var xhr = null
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest() //常用浏览器自带
} else {
xhr = new ActiveXObject("Microsoft.XMLHttp") //IE6自带
}
console.log(xhr.readystate) // 0
xhr.open("get", "http://www.baidu.com", true) // 第三个参数 true 代表异步
console.log(xhr.readystate) // 1
// 这部分是该部分内容新增
xhr.onreadystatechange = function () {
console.log(xhr.readystate)
//readystate 为xhr的一个属性,其会随着ajax发送的进度变化而变化,刚开始创建xhr时是0,open之后是1,如示例
// readystate == 4时 表示请求完成 已经接收到数据
// status == 200 网络请求 ,请求到的结果会有一个状态码,来表示这个请求是否正常
// 200表示请求成功
// http状态码
// 2**表示成功
// 3**表示重定向
// 4**表示客户端错误,404页面没有找到
// 5**表示服务端错误
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText)
//如果有返回的结果,返回的结果存在xhr.responseText这个属性里
var data = JSON.parse(xhr.responseText)
// 将jsonz数据转换为js对象
//扩展知识:将js对象转换为json数据
//JSON.stringify(data)
}
}
xhr.send()
//至此就完成了这种方式,既可以用代码控制,而且页面不会跳转,并且服务端返回的结果我们可以用JS继续处理
二. 跨域:
什么是跨域:
- 页面本身与要请求数据的网址 —— 协议 域名 端口号 有任意一个不一样的 就算跨域
跨域访问资源:
- 哪些东西属于资源
- js文件,但是js文件是允许被跨域请求的
- css文件 ,jpg,png 等(src属性的资源都是可以被跨域请求的,href 资源大部分都是可以被跨域请求的)
例 —— img请求:
<img src="https://gss0.bdstatic.com/94o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike92%2C5%2C5%2C92%2C30/sign=4b1e0ff44da98226accc2375ebebd264/faf2b2119313b07e6a5add8902d7912396dd8c48.jpg" alt="">
// 虽然也是跨域的但是是可以被跨域请求的
2. 哪些资源算跨域请求的资源
- 后端接口的数据
- 其他域的cookie
- 其他域的缓存
解决跨域的方法 —— 虽然跨域了,但是我们依然需要这个数据:
- 后端(这里的后端,是指的别人的后端)配合我们进行跨域:
- JSONP(正常情况下,返回的数据都是JSON格式,JSONP是一种特殊的格式)
- 后端设置Access-Control-Allow-Origin属性以支持跨域
- 后端不配合我们进行跨域
- iframe进行跨域 (只能显示不能控制)
例:
<iframe src="https://www.baidu.com" frameborder="0" width="600" height="600"></iframe>
//虽然跨域,但是可以跨域请求到
- 通过后端代理(指自己的后端)的
JSONP的使用:
- JSONP的特殊格式
- 发送的时候,会带上一个参数callback
- 返回的结果不是Json 而是 callback(json数据)
- 使用JQ发送jsonp请求
-
$.ajax({ url:"https://www.baidu.com", type:"get", dataType:"jsonp" //返回类型 success : function(data){ //成功后返回的数据 console.log(data); } }) //JSonp跨域,只能使用get方法, 如果我们设置的是post方法,JQuery会自动转换为get方法 //但不是在JSONP里面只能使用get方法 //首先JQuery会先判断是否同源,若同源,那么设置的是什么就是什么 //若不是同源,无论设置的是什么,都改为get
封装ajax:
//封装
function ajax(mode, url, callback, data, flag) {
// 兼容
var xhr = null
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest() //常用浏览器自带
} else {
xhr = new ActiveXObject("Microsoft.XMLHttp") //IE6自带
}
//事件
xhr.onreadystatechange = function () {
if (xhr.readystate == 4) {
if (xhr.status == 200) {
callback(xhr.responseText)
} else {
console.log('error')
}
}
}
//格式要求
mode = mode.toUpperCase(); // 将请求方式变为大写的
if (mode == 'GET') {
// get请求要把请求参数拼接到地址里面
xhr.open(mode, url + '?' + data, flag) // 第三个参数 true 代表异步
xhr.send()
} else if (mode == 'POST') {
xhr.open(mode, url, flag)
// 设置Content-type 请求头 ,设置成相应的数据格式, 此处为数据传送的编码格式
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
//post请求必须把请求参数放到请求体里面
xhr.sed(data)
}
}
补充跨域知识
-
解决跨域的两种方法:
- 方法一:整合到一个域
- 方法二:后端修改跨域策略【配置Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Hearders】
-
使用方法二。引发跨域的解决方式
- 协议、域名、端口 不同引发的跨域,可以通过配置Access-Control-Allow-Origin、结合白名单的方式来解决
- 请求方式不符合也会引发跨域,通过上述配置后,只能get或post通过跨域,例如当请求方式为put,就还需要通过配置Access-Control-Allow-Methods来解决 【'GET,POAST,PUT、等'】
- 自定义headers的属性时,也会引发跨域,同理通过配置Access-Control-Allow-Hearders来解决
在使用vite搭建的vue项目中解决跨域
- 开发环境中的配置
// vite.config.js
export default defineConfig({
server:{
port:8000, //【前端的端口】
//允许局域网访问vite服务
host:'0.0.0.0',
open:true,
proxy:{
// 当请求,含有'api'路径的接口时,代理转发到target配置的服务
'api':{
//目的地,即想要请求的接口路径,【后端的服务接口】
target:'http://localhost:8080'
}
}
},
})
// 配置完以上这些后, 当我们请求了接口,就会转换到target服务
//home.vue 比如首页请求了接口
axios({
url:'/api/2222', // 这里直接使用相对路径就好
method:'get',
timeout:1000
})
// 比如 请求网址为 http://localhost:8000
// 第一步:首先会经过 页面路径的8000端口 , 8000端口是vite服务。
// 第二步:会转发到target配置的路径
- 生产环境中的配置,一般是用nginx
nginx反向代理
- 反向代理概念:
- 反向代理(Reverse Proxy)是Nginx的核心功能之一,它充当客户端与后端服务器之间的“中间人”,接收客户端请求并转发到内部网络中的目标服务器
- 基础配置:
server {
listen 80;
server_name your_domain.com; # 替换为你的域名或IP location /
{
proxy_pass http://localhost:8080; # 指向后端服务地址
proxy_set_header Host $host; # 传递原始Host头
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
vite处理跨域
同源策略基本介绍
- 仅在浏览器发生,是浏览器的规则
- http交互默认情况下,只能在同协议,同域名,同端口的两台终端进行
https://www.baidu.com:443/index.html (我家)
https://www.360.com:443/getUserInfo (你家)
// 我去你家那东西,肯定是不行的,但可以通过门锁,人脸识别等
// 浏览器就相当于门锁或人脸识别
// 当尝试去拿,就会调用浏览器的网络模块
// 浏览器发现两个不一样,就会想你百度去拿360的东西,人家360有没有允许,这时的浏览器是不知道,360是否允许百度访问
// 浏览器会先放行,请求开始传输,达到360服务器
// 响应(360和浏览器说,百度是自己的朋友),那这时,浏览器就会允许访问,也就是说只要360同意,浏览器就会不管
// 但是,假如360有点憨,只要是个请求过来,他都会把响应给出去,但是如果是朋友的话,他会额外加个标记
// 当响应来到以后,浏览器发现360没有特殊强调说百度是自己的朋友,那浏览器说不好意思了,这玩意我收了,你拿不到,同时通知一下百度说:人家360没说你是他朋友,如果你想要的话,你去和他私下聊聊,让他来证明你是他朋友,这个时候,我(指浏览器)再给你
// 跨域(仅发生在浏览器):当a源浏览器的网页向b源的服务器地址 (不满足同源策略,满足同源限制)请求对应消息,就会产生跨域。跨域请求默认情况下会被浏览器拦截,除非对应的请求服务器出具标记说,这个a源是允许拿b源的东西的
- 注:跨域限制是:服务器已经响应了东西,但是浏览器(作为保安)不给你,不是说服务器没有给。
- 即浏览器在发送请求的时候,是不可能拦截的,因为他不确保请求的服务器地址不允许跨域。所以只能在响应的时候拦截,无法在请求的时候拦截
解决方式(vite):
server: { // server 代表开发服务器中的配置
port: 8000, //【前端的端口】
//允许局域网访问vite服务
host: '0.0.0.0',
open: true,
proxy: { // proxy 代表配置跨域解决方案
// 当请求,含有'api'路径的接口时,代理转发到target配置的服务
api: { // 以后再遇到 /apikai
//目的地,即想要请求的接口路径,【后端的服务接口】
target: 'http://localhost:8080',
changeOrigin:true // 换源
},
},
- 当请求一个 /api 接口的过程
- 首先浏览器会先帮我们做一步拼接
- http://127.0.0.1:5174/api 浏览器拼接完,会去找vite
- vite发现这个path (即去掉域名,在这里就是/api),有配置跨域代理策略,然后会根据策略的描述对象,进行再次请求
- 比如策略里面配置了 /api ,之后就会去找target配置的属性,及rewrite。
- 然后开发服务器,就会请求目标的服务器(服务器之间没有同源策略)
- 开发时态:我们一般利用 构建工具或者脚手架或者第三方库的proxy代理,或者我们自己搭一个开发服务器来解决这个问题
- 但是到了生产,这些就没有用了,生产环境没有vite开发服务器
解决生产时态的跨域
- 生产环境一般不会有跨域问题
- 比如我们现在 www.byabc.com 在这个目录下
- 我们会把dist目录完全给到后端或运维
- 他们会把我们的后端服务+前端代码 放到一个域下面的
- 比如后端代码在 www.byabc.com/api/getUuse…
- 前端代码在www.byabc.com/dist/index.…
- 以上这种情况就不会跨域
- 但是跨部门的话,就可能会有跨域问题,比如百度,百度百科,百度文科等
百度百科 https://baike.baidu.com 用户信息 https://baidu.com/api/userInfo // 这种情况下,运维是不会放在同一个域名下的,会各自维护 // 这种时候就要采取以下方法了 - 一般是交给后端去处理跨域
- nginx:代理服务器
- 配置身份标记:就是Access-Control-Allow-Origin :这代表哪些域是我们的朋友