14.相信面试会用到的HTTP请求(未完待续...)

189 阅读5分钟

HTTP请求的基本过程:

  1. 浏览器端服务器端发送HTTP请求(请求报文)
  2. 后台服务器接收到请求后,处理请求,向浏览器端返回HTTP响应(响应报文)
  3. 浏览器端接收到响应,解析显示响应体调用响应回调函数

第一章:HTTP请求

一、原生XHR(xhr请求使用浏览器中遵守同源策略的Ajax引擎实现)🔺

AJAX

  • AJAX全称为Asynchronous Javascript And XML,就是异步的JS和XML
  • 通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:页面无刷新获取数据
  • AJAX不是新的编程语言,而是将现有的标准组合在一起使用的新方式
  • 原生xhr和原生fetch都可以发送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解决跨域

  1. 后端配置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')
})
  1. 后端使用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(基本promise封装XHR的异步Ajax请求库)

前端流行的Ajax请求库,react/vue都推荐使用axios发Ajax请求

axios特点:

  1. 基本promise的异步Ajax请求库
  2. 浏览器端/node端都可以使用
  3. 支持请求/响应拦截器
  4. 支持请求取消
  5. 请求/响应数据转换
  6. 批量发送多个请求
<!--
    1.axios调用的返回值是Promise实例
    2.成功的值叫response,失败的值叫error
    3.axios成功的值是一个axios封装的response对象,服务器返回的数据在response.data中
-->
<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);}
    )
    
}

四、原生Fetch(ES6)(基本promise封装的非xhr的Ajax请求)

浏览器端发请求: 只有XHR或fetch发出的才是ajax请求其它所有的都是非ajax请求🔺
fetch是一个原生函数API,不再使用XmlHttpRequest对象提交ajax请求
Fetch符合关注分离:1. fetch().then先接收请求状态 → 2. 后获取结果数据response.json
原版:

fetch(url,{
    method: “POST",
    body: JSON.stringify(data),
    headers: {
        "Content-Type": "application/json" 
        credentials: "same-origin'
    }).then(function(response) {
        response.status
        response.statusText
        response.headers
        response.url
        return response.text( )
    }, function(error) {
        error.message
})

简化1:

fetch(/api/search?q=${keyWord})
.then(
    response => {
        console.log('联系服务器成功了');
        return response.json()
    }
).then(
    response => {console.log('获取数据成功了',response);}
).catch(
    (error)=>{conso1e.1og(error);}
)

简化2:

async()=> {
    try {
        const response= await fetch(/api/search?q=${keyWord})  // 得到Promise状态
        const data = await response.json()  // 提取响应数据
        console.log(data);
    } catch (error) {
        console.log('请求出错',error);
    }
}

第二章:相关内容

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请求方式与请求参数

请求方式

  1. GET(简单请求 索取): 从服务器端读取数据→查(R)
  2. POST(简单请求 提交): 向服务器端添加新数据→增(C)
  3. PUT(复杂请求 修改): 更新服务器端已存在的数据→改(U)
  4. DELETE(复杂请求 删除): 删除服务器端数据→删(D)
  5. HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
  6. CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
  7. OPTIONS(复杂请求put和delete发送前携带的嗅探请求)允许客户端查看服务器的性能
  8. TRACE 回显服务器收到的请求,主要用于测试或诊断

请求参数

  1. query 参数(查询字符串参数)

    1. 参数包含在请求地址中,格式为: http://localhost:0000?name=tom&age=18
    2. 敏感数据不要用query参数,因为参数是地址的一部分,比较危险
    3. query参数又称“查询字符串参数”,编码方式为unlencoded
  2. params 参数

    1. 参数包含在请求地址中,格式为: http://localhost:0000/add_person/tom/18
    2. 敏感数据不要用params参数,因为参数是地址的一部分,比较危险
  3. 请求体参数

    1. 参数包含在请求体中,可通过浏览器开发工具查看
    2. 常用的两种格式:
      • 格式一: urlencoded格式👉 例如: hame=tom&age=18👉 对应请求头Content-Type: application/x-www-form-urlencoded
      • 格式二: json格式👉 例如: {"name:"tom", "age": 12)👉 对应请求头: Content-Type: application/json 特别注意: GET请求不能携带请求体参数,因为GET请求没有请求体