14.HTTP请求(原文在掘金更新,同名“我的GIS”)
HTTP请求
一、原生XHR(xhr请求使用浏览器中遵守同源策略的Ajax引擎实现)🔺
AJAX
AJAX全称为Asynchronous Javascript And XML,就是异步的JS和XML
通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:页面无刷新获取数据
AJAX不是新的编程语言,而是将现有的标准组合在一起使用的新方式
AJAX的优点
可以无需刷新页面而与服务器端进行通信
允许你根据用户事件来更新部分页面内容
AJAX的缺点
没有浏览历史,不能回退
存在跨域问题
SEO(搜索引擎优化)不友好
AJAX核心对象
"XMLHttpRequest"👉AJAX的所有操作都是通过该对象进行的
流程
<button id="btn">点我发送请求(原生js-ajax-get)</button> <div id="content"></div> <script type="text/javascript"> const btn = document.getElementById('btn'); const content = document.getElementById('content'); let isLoading //给按钮绑定监听 btn.onclick = ()=>{ // if(isLoading) xhr.abort() // 避免多次请求 // 1. 创建XHR实例对象 const xhr = new XMLHttpRequest(); // xhr内部有5种状态,值分别为: 0、1、2、3、4 // 绑定监听:xhr实例对象在实例出来状态是0, 收到返回数据状态为4 xhr.onreadystatechange = ()=>{ if(xhr.readyState === 4){ if(xhr.status >= 200 && xhr.status < 300){ console.log(xhr.response); content.innerHTML = `<h3>${xhr.response}</h3>`; } } } // 2. GET方式:指定method、url、携带params(服务端路径占位符/:name)或query参数 xhr.open('GET', 'http://127.0.0.1:8080/test_get?name="张三"&age=18'); // 3. 发送请求 xhr.send(); // is isLoading = true } </script> 复制代码
// POST方式:指定method、url、携带params、query或body(主要)参数 xhr.open('POST', 'http://127.0.0.1:8080/test_post') // 务必要带请求体类型(编码形式):urlencoded或json(application/json) xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded') // 请求体携带: xhr.send('name=张三&age=18') // const p = {name:"张三", age:18}; xhr.send(JSON.stringify(p)); 复制代码
xhr其他配置(API)
// responseType 用于指定返回数据的格式(解析方式) xhr.responseType = 'json' // 配置出错回调 xhr.onerror = ()=>{ console.log("请求出错了!") } // 设定超时时间 xhr.timeout = 2000 // 配置超时回调 xhr.ontimeout = ()=>{ console.log("请求超时了!") } 复制代码
缺点:代码繁琐
二、跨域
JSONP(JSON with Padding)解决跨域🔺
利用不受同源策略CORS限制的script标签访问跨域链接(仅支持get方式),绕过有跨域限制的xhr 后端:
app.get('/test_jsonp', (request, response)=>{ const {callback} = request.query const person = [{name:'tom', age:18}, {name:'张三', age:18}] response.send(`${callback}(${JSON.stringify(person)})`) // js对象转换成json字符串 }) 复制代码
前端:
<button id="btn">点我获取数据</button> <script> const btn = document.getElementById('btn') btn.onclick = ()=>{ // 1.创建script节点 const scriptNode = document.createElement('script') // 2.给节点指定src属性(请求地址)(可使用query参数传递函数名) scriptNode.src = 'http://localhost:8080/test_jsonp?callback=demo' // 3.将节点放入页面 document.body.appendChild(scriptNode) window.demo = (a)=>{ console.log(a); } // 4.请求完毕,移除节点 document.body.removeChild(scriptNode) } </script> 复制代码
cors中间件后端express解决跨域
后端配置setHeader()跨域响应头方法:
简单请求(get; post):
app.get('/test_get ',(request, response)=>{ response.setHeader('Access-Control-Allow-Origin','*') response.setHeader('Access-Control-Expose-Headers' ,'*') response.send('hello_test_get') }) 复制代码
复杂请求(put; delete 这两种请求会有预请求options/嗅探请求):
// 预请求处理 app.options('/test_put', (request, response)=>{ // *通配符,可替换为指定前端请求源地址 response.setHeader('Access-Control-Allow-Origin','*') response.setHeader('Access-Cpntrol-Expose-Headers','*') response.setHeader('Access-Control-Allow-Methods','*') response.send() }) app.put('/test_put', (request, response)=>{ response.setHeader('Access-Control-Allow-Origin','*') response.setHeader('Access-Control-Expose-Headers','*') response.send('hello_test_put') }) 复制代码
后端使用cors处理跨域:
const cors = require('cors') const app = express() app.use(cors()) // 使用中间件处理跨域 复制代码
三、jQuery(封装Ajax/依赖于XHR)(一般http请求:非Ajax请求)
完整版
<script> const btn1 = $('#btn1') const btn2 = $('#btn2') const content = $('#content') btn1.click(()=>{ // 使用jQuery发送ajax-get请求(完整版) $.ajax({ url: 'http://127.0.0.1:8080/jquery_get', // 请求地址 method: 'GET', // 请求方式 data: {school: 'atguigu'}, // 携带的数据 dataType: 'json', // 配置响应数据格式 timeout: 200, // 超时时间 success: (result, reponseText, xhr)=>{ content.append(<div>姓名: ${result.name}, 年龄: ${result.age}</div>) }, // 成功的回调 error: ()=>{console.log("请求出错了!")} // 失败的回调 }) }) </script> 复制代码
精简版
$.get('http://127.0.0.1:8080/jquery_get', {school: 'atguigu'}, (data)=>{ console.log(data) // 成功的回调; },'json') 复制代码
缺点:回调地狱问题(需借助Promise解决)
$.get('http://127.0.0.1:8080/jquery_get_1', {school_1: 'atguigu1'}, (data)=>{ console.log(data) // 成功的回调; $.get('http://127.0.0.1:8080/jquery_get_2', {school_2: 'atguigu2'}, (data)=>{ console.log(data) // 成功的回调; $.get('http://127.0.0.1:8080/jquery_get_3', {school_3: 'atguigu3'}, (data)=>{ console.log(data) // 成功的回调; },'json') },'json') },'json') 复制代码
封装jsonp跨域
<script> const btn = $('#btn') btn.click(()=>{ $.getJSON('http://localhost:8080/test_jsonp?callback=?',{参数},(data)=>{ console.log(data); }) }) </script> 复制代码
四、axios(封装XHR)(一般http请求:非Ajax请求)
前端流行的Ajax请求库,react/vue都推荐使用axios发Ajax请求 axios特点:
基本promise的异步Ajax请求库
浏览器端/node端都可以使用
支持请求/响应拦截器
支持请求取消
请求/响应数据转换
批量发送多个请求
<!-- 1.axios调用的返回值是Promise实例 2.成功的值叫response,失败的值叫error 3.axios成功的值是一个axios封装的response对象,服务器返回的数据在response.data中 --> <body> <button id="btn1">获取</button> <script type= "text/javascript"> // 获取按钮 const btn1 = document.getElementById('btn1') // 发送GET请求不携带参数 btn1.onclick = ()=>{ const result = axios({ url:'http://localhost: 5000/persons', // 请求地址 method: 'GET', // 请求方式 result.then( response => {console.log('请求成功了', response.data);}, error => {console.log('请求失败了', error);} ) } </script> </body> 复制代码
四、fetch(Ajax请求)
复制代码
http状态码
分类
1xx:服务器已经收到了本次请求,但是还需要进一步的处理才可以
2xx:服务器已经收到了本次请求,且已经分析、处理等,最终处理完毕
3xx:服务器已经接收到了请求,还需要其他的资源,或者重定向到其他位置,甚至交给其他服务器处理
4xx:一般指请求的参数或者地址有错误,出现了服务器无法理解的请求(一般是前端的问题)
5xx:服务器内部错误(不是因为请求地址或者请求参数不当造成的),无法响应用户请求(一般是后端人员的问题)
常见的状态码
200:成功
301:重定向,被请求的旧资源永久移除了(不可以访问了),将会跳转到一个新资源,搜索引擎在抓取新内容的同时也将旧的网址重定向为新网址
302:重定向,被请求的旧资源还在(仍然可以访问),但会临时跳转到一个新资源,搜索引擎会抓取新的内容而保留旧网址
304:请求资源重定向到缓存中(命中了协商缓存)
404:资源未找到,一般是客户端请求了不存在的资源
500:服务器收到了请求,但是服务器内部产生了错误
502:连接服务器失败(服务器在处理一个请求的时候,或许需要其他的服务器配合,但是联系不上其他的服务器了
API分类
1.REST API(restful风格的API)
①发送请求进行CRUD哪个操作由请求方式来决定 ②同一个请求路径可以进行多个操作 ③请求方式会用到GET/POST/PUT/DELETE
const app = express() app.get('/person', (req,res)=>{ res.send('数据接收!') }) app.post('/person',(req,res)=>{ res.send('添加数据') }) app.put('/person',(req,res)=>{ res.send('修改数据') }) app.delete('/person',(req,res)=>{ res.send('删除数据') }) app.listen(8090, (error)=>{ if(!error) console.log('服务器开启'); else console.log(err); }) 复制代码
2.非REST API (restless风格的API)
①请求方式不决定请求的CRUD操作 ②一个请求路径只对应一个操作 ③一般只有GET/POST
const app = express() app.get('/get_person',(req,res)=>{ res.send('数据接收!') }) app.post('/add_person',(req,res)=>{ res.send('添加数据') }) app.post('/update_person',(req,res)=>{ res.send('修改数据') }) app.post('/delete_person',(req,res)=>{ res.send('删除数据') }) app.listen(8090, (error)=>{ if(!error) console.log('服务器开启'); else console.log(err); }) 复制代码
HTTP1.1请求方式与请求参数
请求方式
GET(简单请求 索取): 从服务器端读取数据→查(R)
POST(简单请求 提交): 向服务器端添加新数据→增(C)
PUT(复杂请求 修改): 更新服务器端已存在的数据→改(U)
DELETE(复杂请求 删除): 删除服务器端数据→删(D)
HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
OPTIONS(复杂请求put和delete发送前携带的嗅探请求)允许客户端查看服务器的性能
TRACE 回显服务器收到的请求,主要用于测试或诊断
请求参数
query 参数(查询字符串参数)
参数包含在请求地址中,格式为: http://localhost:0000?name=tom&age=18
敏感数据不要用query参数,因为参数是地址的一部分,比较危险
query参数又称“查询字符串参数”,编码方式为unlencoded
params 参数
参数包含在请求地址中,格式为: http://localhost:0000/add_person/tom/18
敏感数据不要用params参数,因为参数是地址的一部分,比较危险
请求体参数
格式一: urlencoded格式👉 例如: hame=tom&age=18👉 对应请求头Content-Type: application/x-www-form-urlencoded
格式二: json格式👉 例如: {"name:"tom", "age": 12)👉 对应请求头: Content-Type: application/json 特别注意: GET请求不能携带请求体参数,因为GET请求没有请求体
参数包含在请求体中,可通过浏览器开发工具查看
常用的两种格式:
格式一: urlencoded格式👉 例如: hame=tom&age=18👉 对应请求头Content-Type: application/x-www-form-urlencoded
格式二: json格式👉 例如: {"name:"tom", "age": 12)👉 对应请求头: Content-Type: application/json 特别注意: GET请求不能携带请求体参数,因为GET请求没有请求体