HTTP知识
HTTP(hypertext transport protocol)协议『超文本传输协议』,协议详细规定了浏览器和万维网服务器之间互相通信的规则。
请求报文
| 请求行: GET、POST /s?ie=utf-8...(url的一长串参数) HTTP/1.1 |
| 请求头: Host: atguigu.com |
| Cookie: name=guigu |
| Content-type: application/x-www-form-urlencoded |
| User-Agent: chrome 83 |
| ... |
| |
| 空行 |
| 请求体: username=admin&password=admin (Post、Put有) |
复制
点击原始才可看到请求行等详情信息。
Get请求载荷:url的发送的json格式参数。
Post请求体:发送的表单数据

响应报文
| 响应行: 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> |
复制

响应体:这里返回的是HTML文本,显示网页。
原生AJAX
AJAX简介
AJAX 全称为 Asynchronous JavaScript And XML, 就是异步的 JS 和 XML。
XML简介
XML 可扩展标记语言。
XML 被设计用来传输和存储数据。
XML 和 HTML 类似, 不同的是 HTML 中都是预定义标签, 而 XML 中没有预定义标签,全都是自定义标签, 用来表示一些数据
| <student> |
| <name>孙悟空</name> |
| <age>18</age> |
| <gender>男</gender> |
| </student> |
复制
现在已经被 JSON 取代了。
| { |
| "name":"孙悟空", |
| "age":18, |
| "gender":"男" |
| } |
复制
AJAX的使用
核心对象:
XMLHttpRequest: AJAX 的所有操作都是通过该对象进行的。
使用步骤
| |
| var xhr = new XMLHttpRequest(); |
| |
| |
| xhr.open(method, url); |
| |
| |
| xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); |
| |
| |
| xhr.send(body) |
| |
| 4) 接收响应 |
| |
| |
| xhr.onreadystatechange = function (){ |
| if(xhr.readyState == 4 && xhr.status == 200){ |
| var text = xhr.responseText; |
| console.log(text); |
| } |
| } |
复制
get请求
客户端:
| <body> |
| <button>点击发送请求</button> |
| <div id="result"></div> |
| |
| <script> |
| |
| const btn = document.getElementsByTagName('button')[0]; |
| const result = document.getElementById("result"); |
| |
| btn.onclick = function(){ |
| |
| const xhr = new XMLHttpRequest(); |
| |
| |
| xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300'); |
| |
| |
| xhr.send(); |
| |
| |
| |
| |
| |
| |
| |
| xhr.onreadystatechange = function(){ |
| |
| if(xhr.readyState === 4){ |
| |
| |
| if(xhr.status >= 200 && xhr.status < 300){ |
| |
| |
| |
| |
| |
| |
| |
| result.innerHTML = xhr.response; |
| }else{ |
| |
| } |
| } |
| } |
| |
| |
| } |
| </script> |
| </body> |
复制
服务端:
| |
| const express = require('express'); |
| |
| |
| const app = express(); |
| |
| |
| |
| |
| app.get('/server', (request, response) => { |
| |
| response.setHeader('Access-Control-Allow-Origin', '*'); |
| |
| response.send('HELLO AJAX - 2'); |
| }); |
| |
| |
| app.listen(8000, () => { |
| console.log("服务已经启动, 8000 端口监听中...."); |
| }); |
复制
post请求
| xhr.open('POST', 'http://127.0.0.1:8000/server'); |
| xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); |
| xhr.setRequestHeader('name','atguigu'); |
| |
| xhr.send('a=100&b=200&c=300'); |
| |
| |
| |
| |
| app.post('/server', (request, response) => { |
| response.setHeader('Access-Control-Allow-Origin', '*'); |
| response.setHeader('Access-Control-Allow-Headers', '*'); |
| response.send('HELLO AJAX POST'); |
| }); |
复制
| |
| |
| app.all('/server', (request, response) => { |
| }); |
复制
返回Json类型
| |
| const xhr = new XMLHttpRequest(); |
| |
| |
| xhr.responseType = 'json'; |
| |
| xhr.open('GET','http://127.0.0.1:8000/json-server'); |
| xhr.send(); |
| xhr.onreadystatechange = function(){ |
| if(xhr.readyState === 4){ |
| if(xhr.status >= 200 && xhr.status < 300){ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| console.log(xhr.response); |
| result.innerHTML = xhr.response.name; |
| } |
| } |
| } |
| |
| |
| |
| app.all('/json-server', (request, response) => { |
| response.setHeader('Access-Control-Allow-Origin', '*'); |
| response.setHeader('Access-Control-Allow-Headers', '*'); |
| |
| const data = { |
| name: 'atguigu' |
| }; |
| |
| let str = JSON.stringify(data); |
| response.send(str); |
| }); |
复制
超时与网络异常
| |
| btn.addEventListener('click', function(){ |
| const xhr = new XMLHttpRequest(); |
| |
| xhr.timeout = 2000; |
| |
| xhr.ontimeout = function(){ |
| alert("网络异常, 请稍后重试!!"); |
| } |
| |
| xhr.onerror = function(){ |
| alert("你的网络似乎出了一些问题!"); |
| } |
| |
| xhr.open("GET",'http://127.0.0.1:8000/delay'); |
| xhr.send(); |
| xhr.onreadystatechange = function(){ |
| if(xhr.readyState === 4){ |
| if(xhr.status >= 200 && xhr.status< 300){ |
| result.innerHTML = xhr.response; |
| } |
| } |
| } |
| }) |
| |
| |
| |
| app.all('/delay', (request, response) => { |
| response.setHeader('Access-Control-Allow-Origin', '*'); |
| response.setHeader('Access-Control-Allow-Headers', '*'); |
| setTimeout(() => { |
| response.send('延时响应'); |
| }, 3000) |
| }); |
复制
取消请求
| // 客户端 |
| <button>点击发送</button> |
| <button>点击取消</button> |
| <script> |
| |
| const btns = document.querySelectorAll('button'); |
| let x = null; |
| |
| btns[0].onclick = function(){ |
| x = new XMLHttpRequest(); |
| x.open("GET",'http://127.0.0.1:8000/delay'); |
| x.send(); |
| } |
| |
| |
| btns[1].onclick = function(){ |
| x.abort(); |
| } |
| </script> |
复制
解决重复请求问题
| <button>点击发送</button> |
| <script> |
| |
| const btns = document.querySelectorAll('button'); |
| let x = null; |
| |
| let isSending = false; |
| |
| btns[0].onclick = function(){ |
| |
| if(isSending) x.abort(); |
| x = new XMLHttpRequest(); |
| |
| isSending = true; |
| x.open("GET",'http://127.0.0.1:8000/delay'); |
| x.send(); |
| x.onreadystatechange = function(){ |
| |
| if(x.readyState === 4){ |
| |
| isSending = false; |
| } |
| } |
| } |
| </script> |
复制
JQuery发送AJAX
get请求
| $.get(url, [data], [callback], [type]) |
| url:请求的 URL 地址。 |
| data:请求携带的参数。 |
| callback:载入成功时回调函数。 |
| type:设置返回内容格式, xml, html, script, json, text, _default。 |
复制
| |
| $('button').eq(0).click(function(){ |
| |
| $.get('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){ |
| console.log(data); |
| },'json'); |
| }); |
| |
| |
| |
| app.all('/jquery-server', (request, response) => { |
| response.setHeader('Access-Control-Allow-Origin', '*'); |
| response.setHeader('Access-Control-Allow-Headers', '*'); |
| |
| const data = {name:'尚硅谷'}; |
| response.send(JSON.stringify(data)); |
| }); |
复制
post请求
| $.post(url, [data], [callback], [type]) |
| url:请求的 URL 地址。 |
| data:请求携带的参数。 |
| callback:载入成功时回调函数。 |
| type:设置返回内容格式, xml, html, script, json, text, _default。 |
复制
| $('button').eq(1).click(function(){ |
| |
| $.post('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){ |
| console.log(data); |
| }); |
| }); |
复制
JQuery通用方法发送请求
| $('button').eq(2).click(function(){ |
| $.ajax({ |
| |
| 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 |
| } |
| }); |
| }); |
复制
aioxs发送请求
https://github.com/axios/axios
特点
- Make XMLHttpRequests from the browser
- Make http requests from node.js
- Supports the Promise API (支持 ES6 Promise API)
- Intercept request and response
- Transform request and response data
- Cancel requests
- Automatic transforms for JSON data (自动转换JSON数据)
- 🆕 Automatic data object serialization to
multipart/form-data
and x-www-form-urlencoded
body encodings - Client side support for protecting against XSRF
| axios.get(url[, config]) |
| axios.post(url[, data[, config]]) |
| axios.put(url[, data[, config]]) |
| axios.delete(url[, config]) |
复制
Get请求
| |
| const btns = document.querySelectorAll('button'); |
| |
| |
| axios.defaults.baseURL = 'http://127.0.0.1:8000'; |
| |
| btns[0].onclick = function () { |
| |
| axios.get('/axios-server', { |
| |
| params: { |
| id: 100, |
| vip: 7 |
| }, |
| |
| headers: { |
| name: 'atguigu', |
| age: 20 |
| } |
| }).then(data => { |
| |
| console.log(data); |
| }).catch(error => { |
| |
| }).finally(() => { |
| |
| }); |
| } |
复制
响应结果展示:

Post请求
| btns[1].onclick = function () { |
| |
| axios.post('/axios-server', { |
| username: 'admin', |
| password: 'admin' |
| }, { |
| |
| params: { |
| id: 200, |
| vip: 9 |
| }, |
| |
| headers: { |
| height: 180, |
| weight: 180, |
| } |
| }).catch(error => { |
| |
| }).finally(() => { |
| |
| }); |
| } |
复制
通用方法发送请求
| btns[2].onclick = function(){ |
| axios({ |
| |
| method : 'POST', |
| |
| url: '/axios-server', |
| |
| params: { |
| vip:10, |
| level:30 |
| }, |
| |
| headers: { |
| a:100, |
| b:200 |
| }, |
| |
| data: { |
| username: 'admin', |
| password: '123456' |
| } |
| }).then(response => { |
| |
| console.log(response.status); |
| |
| console.log(response.statusText); |
| |
| console.log(response.headers); |
| |
| console.log(response.data); |
| }).catch(error => { |
| |
| }).finally(() => { |
| |
| }); |
| } |
复制
跨域
同源策略
同源策略(Same-Origin Policy)最早由 Netscape 公司提出, 是浏览器的一种安全策略
同源: 协议、 域名、 端口号 必须完全相同。
违背同源策略就是跨域。
同源情况:
| |
| const express = require('express'); |
| |
| const app = express(); |
| |
| app.get('/home', (request, response)=>{ |
| |
| response.sendFile(__dirname + '/index.html'); |
| }); |
| |
| app.get('/data', (request, response)=>{ |
| response.send('用户数据'); |
| }); |
| |
| app.listen(9000, ()=>{ |
| console.log("服务已经启动..."); |
| }); |
| |
| |
复制
| |
| <h1>尚硅谷</h1> |
| <button>点击获取用户数据</button> |
| <script> |
| const btn = document.querySelector('button'); |
| |
| btn.onclick = function(){ |
| const x = new XMLHttpRequest(); |
| |
| x.open("GET",'/data'); |
| x.send(); |
| |
| x.onreadystatechange = function(){ |
| if(x.readyState === 4){ |
| if(x.status >= 200 && x.status < 300){ |
| console.log(x.response); |
| } |
| } |
| } |
| } |
| </script> |
复制
在localhost:9000 端口下的index页面点击button发送请求,这个请求也是本地端口下的服务。因此是同源的。
解决跨域问题
CORS
简介
CORS(Cross-Origin Resource Sharing) , 跨域资源共享。 CORS 是官方的跨域解决方案, 它的特点是不需要在客户端做任何特殊的操作, 完全在服务器中进行处理, 支持get 和 post 请求。 跨域资源共享标准新增了一组 HTTP 首部字段, 允许服务器声明哪些源站通过浏览器有权限访问哪些资源。
工作
CORS 是通过设置一个响应头来告诉浏览器, 该请求允许跨域, 浏览器收到该响应以后就会对响应放行。
使用
后端设置响应头部信息: 在服务端(后端)对应的接口中设置合适的响应头部信息,允许指定域名或允许所有域名访问,如设置 Access-Control-Allow-Origin 为 ‘*’(表示允许所有域名)。
| |
| response.setHeader('Access-Control-Allow-Origin', '*'); |
| |
| |
| |
| response.setHeader('Access-Control-Allow-Headers', '*'); |
| |
| response.setHeader("Access-Control-Allow-Method", '*'); |
复制
其他解决跨域问题:
- 使用代理: 在开发环境下,可以通过配置代理来规避跨域问题。即在前端发送请求时,先将请求发送到自己的服务器(域名前端一致),再由自己的服务器转发请求到目标后端服务,然后将后端服务的响应返回给前端。这种方式需要自己搭建代理服务器。
- 小程序开发工具配置不校验合法域名: 在微信开发者工具中,可以临时关闭域名校验,但这仅适用于开发阶段,上线时不建议关闭域名校验。