js【详解】ajax (含XMLHttpRequest、 同源策略、跨域、JSONP)

ajax 的核心API -- XMLHttpRequest

get 请求

js 复制代码
// 新建 XMLHttpRequest 对象的实例
const xhr = new XMLHttpRequest();
// 发起 get 请求,open 的三个参数为:请求类型,请求地址,是否异步请求( true 为异步,false 为同步)
xhr.open("GET", "/data/test.json", false);

// 定义 xhr 状态改变的处理函数
xhr.onreadystatechange = function () {
  // xhr 的 readyState 属性变为 4
  if (xhr.readyState === 4) {
    // 网络请求返回的状态码为 200
    if (xhr.status === 200) {
      alert(xhr.responseText);
    } else if (xhr.status === 404) {
      // 网络请求返回的状态码为 404
      console.log("404 not found");
    } else {
      console.log("其他情况");
    }
  }
};

// 发出请求,会触发 xhr 状态的改变
xhr.send(null);

post 请求

js 复制代码
// 新建 XMLHttpRequest 对象的实例
const xhr = new XMLHttpRequest();
// open 的三个参数为:请求类型,请求地址,是否异步请求( true 为异步,false 为同步)
xhr.open("POST", "/login", false);

// 定义 xhr 状态改变的处理函数
xhr.onreadystatechange = function () {
  // xhr 的 readyState 属性变为 4
  if (xhr.readyState === 4) {
    // 网络请求返回的状态码为 200
    if (xhr.status === 200) {
      alert(xhr.responseText);
    } else if (xhr.status === 404) {
      // 网络请求返回的状态码为 404
      console.log("404 not found");
    } else {
      console.log("其他情况");
    }
  }
};

// 定义 post 请求的参数
const postData = {
  userName: "朝阳",
  password: "xxx",
};

// 发出请求 -- 参数需转为字符串
xhr.send(JSON.stringify(postData));

XMLHttpRequest 的 readyState 属性

  • 0 ------ UNSET 尚未调用 open方法
  • 1 ------ OPENED open 方法已被调用
  • 2 ------ HEADERS RECEIVED send 方法已被调用,header 已被接收
  • 3 ------ LOADING 下载中,responseText已有部分内容
  • 4 ------ DONE 下载完成

XMLHttpRequest 的 status 属性

即 http 请求的状态码,详见
https://blog.csdn.net/weixin_41192489/article/details/136446539

同源策略

ajax 请求地址的 协议、域名、端口 必须和当前网页的地址相同!

  • 浏览器中的 ajax 请求才有同源策略限制
  • 图片、css文件、js文件的加载,没有同源策略限制,应用如下:
    • 图片用于使用第三方统计服务完成统计打点(如统计网页浏览量)
    • 使用 CDN 加速图片、css文件、js文件
    • <script> 可用于实现 JSONP

跨域

所有的跨域,都必须经过 server 端允许和配合

【考题】哪些 html标签能绕过跨域 ?

  • <a>标签的href属性可以实现跨域链接,但是只能用于GET请求
html 复制代码
<a href="http://baidu.com">跨域链接</a>
  • <img>标签的src属性可以加载跨域图片
html 复制代码
<img src="http://**.jpg" alt="跨域图片">
  • <link>标签的href属性可以加载跨域样式表。
html 复制代码
<link rel="stylesheet" href="http://**.cn/styles.css">
  • <script>标签的src属性可以加载跨域脚本文件,常用于JSONP跨域请求。
html 复制代码
<script src="http://**.cn/api.js"></script>

以上标签和属性只是在特定情况下可以用于跨域请求,具体是否允许跨域请求还要看服务器端是否设置了相应的CORS(跨域资源共享)策略。如果服务器没有设置CORS策略,浏览器会阻止跨域请求。

方案一 JSONP

JSONP 实现跨域的过程:借助 script 标签没有同源策略限制的特点,向跨域的目标服务器加载到需要的数据。

范例:

html 复制代码
 <script>
     window.callback= function (data) {
         console.log(data)
     }
 </script>
 <script src="http://localhost:8008/jsonp.js"></script>

jsonp.js

js 复制代码
callback(
    { name: '朝阳' }
)

借助 script 标签 向目标服务器加载到 jsonp.js 文件,执行 callback 函数,因本地已定义了 callback 函数,便会触发本地 js 代码的执行,获取到 jsonp.js 文件中的数据,从而实现了跨域。

jQuery 实现 jsonp

jQuery 内实现 jsonp 的方式与范例中相同,只是进行了封装。

方案二 跨域资源共享 CORS

服务器设置 http header,即服务器端将指定网址设置为白名单,允许它以指定的方法进行跨域访问。(纯服务端的修改实现,和前端无关)

【考题】手写一个简易的 ajax

js 复制代码
function ajax(url) {
    const p = new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()
        xhr.open('GET', url, true)
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    resolve(
                        JSON.parse(xhr.responseText)
                    )
                } else if (xhr.status === 404 || xhr.status === 500) {
                    reject(new Error('404 not found'))
                }
            }
        }
        xhr.send(null)
    })
    return p
}

使用

js 复制代码
const url = '/data/test.json'
ajax(url)
.then(res => console.log(res))
.catch(err => console.error(err))

【考题】怎么实现跨域?

  • JSONP
  • CORS

实战中实现 ajax 的常用插件

  • jQuery
  • fetch ------ 新增的 Web API
  • axios
相关推荐
星辰中的维纳斯9 分钟前
vue新手入门教程(项目创建+组件导入+VueRouter)
前端·javascript·vue.js
ksuper&12 分钟前
ts和js的关系
javascript
NaRciCiSSuS1 小时前
第一章-JavaScript简介
开发语言·javascript·ecmascript
XF鸭1 小时前
HTML-CSS 入门介绍
服务器·前端·javascript
forwardMyLife2 小时前
element-plus 的form表单组件之el-radio(单选按钮组件)
前端·javascript·vue.js
ilisi_2 小时前
导航栏样式,盒子模型
前端·javascript·css
吉吉安2 小时前
grid布局下的展开/收缩过渡效果【vue/已验证可正常运行】
前端·javascript·vue.js
梦凡尘2 小时前
Vue3 对跳转 同一路由传入不同参数的页面分别进行缓存
前端·javascript·vue.js
柳晓黑胡椒3 小时前
vue3实现多表头列表el-table,拖拽,鼠标滑轮滚动条优化
javascript·vue.js·elementui·el-table
limit for me3 小时前
在uni-app使用vue3使用vuex
javascript·vue.js·uni-app