服务器与Ajax的基本概念

156 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

一. 客户端与服务器

服务器:上网过程中,负责存放和对外提供资源的电脑,叫做服务器。

image.png

客户端:上网过程中,负责获取和消费资源的电脑,叫做客户端。

image.png

二. URL地址

URL(全称是UniformResourceLocator)中文叫统一资源定位符,用于标识互联网上每个资源的唯一存放位置。浏览器只有通过URL地址,才能正确定位资源的存放位置,从而成功访问到对应的资源。 常见的URL举例:

URL地址一般由三部组成:

① 客户端与服务器之间的通信协议

② 存有该资源的服务器名称

③ 资源在服务器上具体的存放位置

image.png

图解客户端与服务器的通信过程

image.png

基于浏览器的开发者工具分析通信过程

image.png

  1. 打开 Chrome 浏览器
  2. Ctrl+Shift+I 打开 Chrome 的开发者工具
  3. 切换到 Network 面板
  4. 选中 Doc 页签
  5. 刷新页面,分析客户端与服务器的通信过程

网页中如何请求数据

  • 数据,也是服务器对外提供的一种资源。只要是资源,必然要通过 请求 – 处理 – 响应 的方式进行获取。 image.png

如果要在网页中请求服务器上的数据资源,则需要用到 XMLHttpRequest 对象。XMLHttpRequest(简称 xhr)是浏览器提供的 js 成员,通过它,可以请求服务器上的数据资源。 最简单的用法 var xhrObj = new XMLHttpRequest()

资源的请求方式

客户端请求服务器时,请求的方式有很多种,最常见的两种请求方式分别为 get 和 post 请求。

  • get 请求通常用于获取服务端资源(向服务器要资源) 例如:根据 URL 地址,从服务器获取 HTML 文件、css 文件、js文件、图片文件、数据资源等

  • post 请求通常用于向服务器提交数据(往服务器发送资源) 例如:登录时向服务器提交的登录信息、注册时向服务器提交的注册信息、添加用户时向服务器提交的用户信息等各种数据提交操作

Ajax

  • Ajax 的全称是 Asynchronous Javascript And XML(异步 JavaScript 和 XML)。

通俗的理解:在网页中利用 XMLHttpRequest 对象和服务器进行数据交互的方式,就是Ajax。AJAX全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据,用户体验更好。

image.png

XML 简介

  • XML 可扩展标记语言。被设计用来传输和存储数据。

  • XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据。

比如说我有一个学生数据:

name = "孙悟空" ; age = 18 ; gender = "男" ;

用 XML 表示:

孙悟空

18

现在已经被 JSON 取代了。

用 JSON 表示:

{"name":"孙悟空","age":18,"gender":"男"}

AJAX 的优点

1)可以无需刷新页面而与服务器端进行通信。

2)允许你根据用户事件来更新部分页面内容。

AJAX 的缺点

1)没有浏览历史,不能回退

2)存在跨域问题(同源)

3)SEO 不友好

HTTP

(1)请求报文:

  • 请求行:Get/Post + 参数字符串 + http版本
  • 请求头: Host: Cookie: Content-type: User-Agent: 空行
  • 体 (GET为空)、post可以不为空

(2)响应报文:

  • 行:http版本 + 状态码 + 响应状态字符串

  • 头: Content-Type: Content-Length: Content-encoding:

        空行
    
  • 体 html文本

AJAX 的使用

核心对象XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的。

使用步骤

1)创建 XMLHttpRequest 对象

var xhr = new XMLHttpRequest();

2)设置请求信息

xhr.open(method, url); 例如: xhr.open('GET','http://localhost:8000/server');

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);

}

}

readystate:

0:表示 XMLHttpRequest 实例已经生成,但是 open()方法还没有被调用。

1:表示 send()方法还没有被调用,仍然可以使用 setRequestHeader(),设定 HTTP请求的头信息。

2:表示 send()方法已经执行,并且头信息和状态码已经收到。

3:表示正在接收服务器传来的 body 部分的数据。

4:表示服务器数据已经完全接收,或者本次接收已经失败了

get方式 url参数设置

xhr.open('GET', 'http://localhost:8000/server?a=100&b=200&c=300');

post方式 url参数设置

xhr.send('a=100&b=200&c=300');

设置请求头

xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

自定义请求头

image.png

对应(server.js): //响应头

response.setHeader('Access-Control-Allow-Headers', '*');

(类型)

image.png

JSON响应数据设置

(1)(html) 添加语句 //设置响应体数据的类型 xhr.responseType = 'json';

text.innerHTML = xhr.response.name;

(2)server.js:

image.png

解决IE缓存(数据更新不及时)问题

更改为(?t=' + Date.now())

xhr.open('GET', 'http://localhost:8000/ie?t=' + Date.now());

超时解决

image.png (模拟时设置server.js超时)

image.png

中断请求

核心代码 xhr.abort();

API总结

  • XMLHttpRequest():创建 XHR 对象的构造函数
  • status:响应状态码值,如 200、404
  • statusText:响应状态文本,如 ’ok‘、‘not found’
  • readyState:标识请求状态的只读属性 0-1-2-3-4
  • onreadystatechange:绑定 readyState 改变的监听
  • responseType:指定响应数据类型,如果是 ‘json’,得到响应后自动解析响应
  • response:响应体数据,类型取决于 responseType 的指定
  • timeout:指定请求超时时间,默认为 0 代表没有限制
  • ontimeout:绑定超时的监听
  • onerror:绑定请求网络错误的监听
  • open():初始化一个请求,参数为:(method, url[, async])
  • send(data):发送请求
  • abort():中断请求 (发出到返回之间)
  • getResponseHeader(name):获取指定名称的响应头值
  • getAllResponseHeaders():获取所有响应头组成的字符串
  • setRequestHeader(name, value):设置请求头

jQuery 中的AJAX

1 get 请求

$.get(url, [data], [callback], [type])

  • url:请求的URL 地址
  • data:请求携带的参数
  • callback:载入成功时回调函数
  • type:设置返回内容格式,xml, html, script, json, text, _default

2 post 请求

$.post(url, [data], [callback], [type])

  • url:请求的URL 地址
  • data:请求携带的参数
  • callback:载入成功时回调函数
  • type:设置返回内容格式,xml, html, script, json, text, _default

3.通用方法

$.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('出错拉~');},
	// 头信息
	headers: {
		c: 300,
		d: 400
	}	
})

补充:快速引入Jquery

(1)bootcdn

(2)搜索jquery image.png

(3)cookie报错解决方法

image.png

axios

    //配置 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: 'atguigu',
                    age: 20
                }
            }).then(value => {
                console.log(value);
            });
        }

        btns[1].onclick = function() {
            axios.post('/axios-server', {
            //请求体
                username: 'admin',
                password: 'admin'
            }, {
                //url 参数
                params: {
                    id: 200,
                    vip: 9
                },
                //请求头参数
                headers: {
                    height: 180,
                    weight: 180,
                }
            });
        }

        btns[2].onclick = function() {
            axios({
                //请求方法
                method: 'POST',
                //url
                url: '/axios-server',
                //url参数
                params: {
                    vip: 10,
                    level: 30
                },
                //头信息
                headers: {
                    a: 100,
                    b: 200
                },
                //请求体参数
                data: {
                    username: 'admin',
                    password: 'admin'
                }
            }).then(response => {
                //响应状态码
                console.log(response.status);
                //响应状态字符串
                console.log(response.statusText);
                //响应头信息
                console.log(response.headers);
                //响应体
                console.log(response.data);
            })
        }

fetch

image.png

跨域问题

1、同源策略与跨域

同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。 如果两个 URL (格式为:protocol://host:port)的 protocol(协议)、port(端口) (如果有指定的话)和 host(主机IP地址) 都相同的话,则这两个 URL 是同源。相关详细描述可参看官方MDN文档。

参考:浏览器的同源策略 - Web 安全 | MDN 、用JSONP解决跨域问题 JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持 get 请求。

JOSNP

1、实现原理

在网页有一些标签天生具有跨域能力,比如:img、link、iframe、script。JSONP 就是利用 script 标签的跨域能力来发送请求的。

当我们在网页中插入 script 标签时,即使 src 属性中所只指向的资源地址与当前网页是跨域的,也能正确执行 src 中的代码。

而 JSONP 正是利用了这一点,在后端代码中返回一个函数的调用(准确的说,返回的应该是一段浏览器能够解析的JS代码),当然,这个函数必须事先已经在前端代码中声明过了,同时传递给该函数的参数就是我们想要返回的数据。

<!-- 前端代码 -->
<script>
  // 处理数据的函数,注意前端一定要实现声明这个函数,否则下方的script标签返回的代码将没法执行
  function handle(data) {
    //获取 result 元素
    const result = document.getElementById('result');
    result.innerHTML = data.name;
  }
</script>
<!-- 向后端请求数据 -->
<script src="http://127.0.0.1:8000/jsonp-server"></script>


// 后端代码 server.js
// jsonp服务
app.all('/jsonp-server', (request, response) => {
  // response.send('console.log("hello jsonp")');
  // data是我们想要给前端返回的数据
  const data = {
    name: '尚硅谷atguigu'
  };
  // 将数据转化为字符串
  let str = JSON.stringify(data);
  // 返回结果,注意这里返回的是一个函数调用,其中的str参数才是我们想要返回的数据
  response.end(`handle(${str})`);
});

2、JSONP实践——检测用户名是否存在

在一个输入框中输入用户名,当输入框失去焦点时向服务端发送AJAX请求,让服务端校验该用户名是否已经存在,并返回校验结果。前端声明一个 handle() 函数来对返回的结果进行处理。

// 后端代码 server.js
// 用户名检测是否存在
app.all('/check-username', (request, response) => {
  // response.send('console.log("hello jsonp")');
  const data = {
    exist: 1,
    msg: '用户名已经存在'
  };
  // 将数据转化为字符串
  let str = JSON.stringify(data);
  // 返回结果,注意这里返回的是一个函数调用,其中的str参数才是我们想要返回的数据
  response.end(`handle(${str})`);
});
<!-- 前端代码 -->
<script>
// 获取 input 元素
const input = document.querySelector('input');
const p = document.querySelector('p');

// 声明 handle 函数用于处理服务端的响应结果
function handle(data){
  input.style.border = "solid 1px #f00";
  // 修改 p 标签的提示文本
  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>

用CORS解决跨域问题

CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。

官方MDN文档是这样描述的:

CORS (Cross-Origin Resource Sharing,跨域资源共享)是一个系统,它由一系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应。

同源安全策略 默认阻止“跨域”获取资源。但是 CORS 给了web服务器这样的权限,即服务器可以选择,允许跨域请求访问到它们的资源。

其他详细说明请参考:CORS - 术语表 | MDN

简单来说,CORS 是通过设置一个响应头 Access-Control-Allow-Origin 来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。

用 CORS 解决跨域问题只需要在服务端代码中通过 response.setHeader() 方法进行相应的响应头设置。客户端正常发送请求即可,不需要做相应的设置。

// 后端代码 server.js
app.all('/cors-server', (request, response) => {
  //设置响应头
  // response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
  response.setHeader("Access-Control-Allow-Origin", "*");
  response.send('hello CORS');
});

如果服务端不设置 Access-Control-Allow-Origin 的话,一旦发生跨域问题就会报以下的错误:

Access to XMLHttpRequest at 'http://127.0.0.1:8000/cors-server' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.