http说明

前后台请求过程

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

请求报文

  • 请求报文

    1
    2
    3
    4
    5
    6
    7
    1). url: 可能带GET请求参数
    2). method: 请求方式
    3). headers: 多个请求头
    Host: www.baidu.com
    Cookie: BAIDUID=AD3B0FA706E; BIDUPSID=AD3B0FA706;
    Content-Type: application/x-www-form-urlencoded
    4). body: 请求体
  • 仅有POST、PUT以及PATCH这三个动词时会包含请求体,而GET、HEAD、DELETE、CONNECT、TRACE、OPTIONS这几个动词时不包含请求体。

    • GET: 从服务器端读取数据
    • POST: 向服务器端添加新数据
    • PUT: 更新服务器端已经数据
    • DELETE: 删除服务器端数据
  • 请求的格式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1). Content-Type: application/x-www-form-urlencoded;charset=utf-8
    用于键值对参数,参数的键值用=连接, 参数之间用&连接
    例如: name=%E5%B0%8F%E6%98%8E&age=12

    2). Content-Type: application/json;charset=utf-8
    用于json字符串参数
    例如: {"name": "%E5%B0%8F%E6%98%8E", "age": 12}

    3). Content-Type: multipart/form-data
    用于文件上传请求

请求头

Header 解释 示例
Accept 指定客户端能够接收的内容类型 Accept: text/plain, text/html,application/json
Accept-Charset 浏览器可以接受的字符编码集。 Accept-Charset: iso-8859-5
Accept-Encoding 指定浏览器可以支持的web服务器返回内容压缩编码类型。 Accept-Encoding: compress, gzip
Accept-Language 浏览器可接受的语言 Accept-Language: en,zh
Accept-Ranges 可以请求网页实体的一个或者多个子范围字段 Accept-Ranges: bytes
Authorization HTTP授权的授权证书 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cache-Control 指定请求和响应遵循的缓存机制 Cache-Control: no-cache
Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) Connection: close
Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 Cookie: $Version=1; Skin=new;
Content-Length 请求的内容长度 Content-Length: 348
Content-Type 请求的与实体对应的MIME信息 Content-Type: application/x-www-form-urlencoded
Date 请求发送的日期和时间 Date: Tue, 15 Nov 2010 08:12:31 GMT
Expect 请求的特定的服务器行为 Expect: 100-continue
From 发出请求的用户的Email From: user@email.com
Host 指定请求的服务器的域名和端口号 Host: www.zcmhi.com
If-Match 只有请求内容与实体相匹配才有效 If-Match: “737060cd8c284d8af7ad3082f209582d”
If-Modified-Since 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
If-None-Match 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 If-None-Match: “737060cd8c284d8af7ad3082f209582d”
If-Range 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag If-Range: “737060cd8c284d8af7ad3082f209582d”
If-Unmodified-Since 只在实体在指定时间之后未被修改才请求成功 If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
Max-Forwards 限制信息通过代理和网关传送的时间 Max-Forwards: 10
Pragma 用来包含实现特定的指令 Pragma: no-cache
Proxy-Authorization 连接到代理的授权证书 Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Range 只请求实体的一部分,指定范围 Range: bytes=500-999
Referer 先前网页的地址,当前请求网页紧随其后,即来路 Referer: http://www.zcmhi.com/archives...
TE 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 TE: trailers,deflate;q=0.5
Upgrade 向服务器指定某种传输协议以便服务器进行转换(如果支持) Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
User-Agent User-Agent的内容包含发出请求的用户信息 User-Agent: Mozilla/5.0 (Linux; X11)
Via 通知中间网关或代理服务器地址,通信协议 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning 关于消息实体的警告信息 Warn: 199 Miscellaneous warning

响应报文

1
2
3
4
5
6
1). 响应状态码: 200/404
2). 多个响应头
Content-Type: text/html;charset=utf-8
Set-Cookie: BD_CK_SAM=1;path=/
3). 响应体
html文本/json文本/js/css/图片...

响应状态码

  • 文档: https://www.runoob.com/http/http-status-codes.html

  • 区间

    1
    2
    3
    4
    5
    1**	信息,服务器收到请求,需要请求者继续执行操作
    2** 成功,操作被成功接收并处理
    3** 需要进一步的操作以完成请求
    4** 客户端错误,请求包含语法错误或无法完成请求
    5** 服务器错误,服务器在处理请求的过程中发生了错误
  • 常见的几个

    1
    2
    3
    4
    5
    200	OK                     请求成功。一般用于GET与POST请求
    201 Created 已创建。成功请求并创建了新的资源
    401 Unauthorized 未授权/请求要求用户的身份认证
    404 Not Found 服务器无法根据客户端的请求找到资源
    500 Internal Server Error 服务器内部错误,无法完成请求

API 分类

  • REST API:

    • 发送请求进行CRUD哪个操作由请求方式来决定
    • 同一个请求路径可以进行多个操作
    • 请求方式会用到GET/POST/PUT/DELETE
  • 非REST API:

    • 请求方式不决定请求的CRUD操作
    • 一个请求路径只对应一个操作
    • 一般只有GET/POST

环境安装

NodeJs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 安装 NVM
C:\Users\fulsun>scoop install nvm

# 使用 NVM 安装 NodeJs
C:\Users\fulsun>nvm list available

| CURRENT | LTS | OLD STABLE | OLD UNSTABLE |
|--------------|--------------|--------------|--------------|
| 14.11.0 | 12.18.4 | 0.12.18 | 0.11.16 |
| 14.10.1 | 12.18.3 | 0.12.17 | 0.11.15 |
| 14.10.0 | 12.18.2 | 0.12.16 | 0.11.14 |
| 14.9.0 | 12.18.1 | 0.12.15 | 0.11.13 |
| 14.8.0 | 12.18.0 | 0.12.14 | 0.11.12 |
| 14.7.0 | 12.17.0 | 0.12.13 | 0.11.11 |
| 14.6.0 | 12.16.3 | 0.12.12 | 0.11.10 |
| 14.5.0 | 12.16.2 | 0.12.11 | 0.11.9 |
| 14.4.0 | 12.16.1 | 0.12.10 | 0.11.8 |
| 14.3.0 | 12.16.0 | 0.12.9 | 0.11.7 |
| 14.2.0 | 12.15.0 | 0.12.8 | 0.11.6 |
| 14.1.0 | 12.14.1 | 0.12.7 | 0.11.5 |
| 14.0.0 | 12.14.0 | 0.12.6 | 0.11.4 |
| 13.14.0 | 12.13.1 | 0.12.5 | 0.11.3 |
| 13.13.0 | 12.13.0 | 0.12.4 | 0.11.2 |
| 13.12.0 | 10.22.1 | 0.12.3 | 0.11.1 |
| 13.11.0 | 10.22.0 | 0.12.2 | 0.11.0 |
| 13.10.1 | 10.21.0 | 0.12.1 | 0.9.12 |
| 13.10.0 | 10.20.1 | 0.12.0 | 0.9.11 |
| 13.9.0 | 10.20.0 | 0.10.48 | 0.9.10 |

This is a partial list. For a complete list, visit https://nodejs.org/download/release


C:\Users\fulsun>nvm install 12.18.4
C:\Users\fulsun>nvm use 12.18.4

# 用来更改npm的镜像
C:\Users\fulsun>npm install nrm
C:\Users\fulsun>nrm ls

* npm -------- https://registry.npmjs.org/
yarn ------- https://registry.yarnpkg.com/
cnpm ------- http://r.cnpmjs.org/
taobao ----- https://registry.npm.taobao.org/
nj --------- https://registry.nodejitsu.com/
npmMirror -- https://skimdb.npmjs.com/registry/
edunpm ----- http://registry.enpmjs.org/


C:\Users\fulsun>nrm test

* npm ---- 353ms
yarn --- 373ms
cnpm --- Fetch Error
taobao - 300ms
nj ----- Fetch Error
npmMirror 1946ms
edunpm - 4610ms

C:\Users\fulsun>nrm use taobao

json-server

1
2
3
4
5
{
"posts": [{ "id": 1, "title": "json-server", "author": "typicode" }],
"comments": [{ "id": 1, "body": "some comment", "postId": 1 }],
"profile": { "name": "typicode" }
}
  • 启动服务器

    执行命令: json-server --watch db.json

  • 浏览器测试访问

    1
    2
    3
    4
    5
    6
    http://localhost:3000/posts
    http://localhost:3000/posts/1

    # 结果
    GET /posts 304 5.540 ms - -
    GET /posts/1 304 3.355 ms - -

其他测试接口

什么是axios

Axios是一个开源的可以用在浏览器端和NodeJS的异步通信框架,主要作用就是实现AJAX异步通信,功能特点如下:

  • 从浏览器中创建 XMLHttpRequests
  • 从node.js创建请求
  • 支持Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF (跨站请求伪造)

为什么使用axios

由于Vue.js是一个视图层框架,作者严格遵循SOC(关注度分离原则),所以Vue.js并不包含AJAX的通信功能,为了能解决通信问题,作者单独开发了 vue-resource的插件,不过在2.0版本以后停止了对该插件的维护,并推荐了Axios框架

初体验

axios 和Vue-axios

  • vue项目中,有些代码使用了 vue-axios和axios

    1
    2
    3
    4
    5
    import Vue from "vue";
    import axios from "axios";
    import VueAxios from "vue-axios";

    Vue.use(VueAxios, axios);
  • vue-axios只是帮你在axios上面再封装了一层,让axios可以直接和Vue组装起来。

  • 推荐使用axios

安装 axios

  • 命令如下:

    1
    2
    3
    npm install --save axios
    # 使用 cdn:
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

axios 引入

  • 在项目中的main.js中引入axios模块

  • 在vue的原型上定义一个属性,等于这个axios,因为组件都继承Vue原型对象

  • 所以在任意组件使用this.$http就相当于使用了axios

    1
    2
    3
    import axios from "axios";
    //修改内部http为axios
    Vue.prototype.$http = axios;

axios基本使用

  • 发送get 请求

    1
    2
    3
    4
    5
    6
    axios.get('http://localhost:3000/posts').then(function(ret){
    # 拿到 ret 是一个对象 所有的对象都存在 ret 的data 属性里面
    // 注意data属性是固定的用法,用于获取后台的实际数据
    // console.log(ret.data)
    console.log(ret)
    })
  • get 请求传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 通过传统的url  以 ? 的形式传递参数
axios.get('http://localhost:3000/posts?id=1&id=2').then(function(ret){
console.log(ret.data)
})

# restful 形式传递参数
axios.get('http://localhost:3000/posts/1').then(function(ret){
console.log(ret.data)
})

# 通过params 形式传递参数
axios.get('http://localhost:3000/posts', {
params: {
id: 1
}
}).then(function(ret){
console.log(ret.data)
})
  • delete 请求传参,传参的形式和 get 请求一样
1
2
3
4
5
6
7
8
// axios.delete('http://localhost:3000/comments/4')
axios.delete('http://localhost:3000/axios', {
params: {
id: 111
}
}).then(function(ret){
console.log(ret.data)
})
  • post 请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 配置post请求的content-type
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

    # 通过选项传递参数
    axios.post('http://localhost:3000/axios', {
    uname: 'lisi',
    pwd: 123
    }).then(function(ret){
    console.log(ret.data)
    })

    # 通过 URLSearchParams 传递参数
    var params = new URLSearchParams();
    params.append('uname', 'zhangsan');
    params.append('pwd', '111');
    axios.post('http://localhost:3000/axios', params).then(function(ret){
    console.log(ret.data)
    })
  • put (更新操作)请求,传参和 post 请求一样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // axios.put('http://localhost:3000/comments/4', {body: 'yyy', postId: 1})

    axios
    .put("http://localhost:3000/axios/123", {
    uname: "lisi",
    pwd: 123,
    })
    .then(function (ret) {
    console.log(ret.data);
    });

axios全局配置

  • 可以在main.js中配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //配置公共的请求头
    axios.defaults.baseURL = "https://127.0.0.1:3000";
    // 配置超时时间
    axios.defaults.timeout = 3000;
    // 配置公共请求头
    axios.defaults.headers.common["Authorization"] = AUTH_TOKEN;
    //配置公共的post的Content-Type
    axios.defaults.headers.post["Content-Type"] =
    "application/x-www-form-urlencoded";
    // post请求头
    axios.defaults.headers.post["Content-Type"] =
    "application/x-www-form-urlencoded;charset=UTF-8";
    // 请求的时候自动携带cookie
    axios.defaults.withCredentials = true;

使用全局示例

  • 启动 json-server --watch db.json

  • main.js引入axios

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import Vue from "vue";
    import App from "./App";
    import router from "./router";

    import axios from "axios";

    // 环境的切换:通过node的环境变量来匹配我们的默认的接口url前缀
    if (process.env.NODE_ENV == "development") {
    axios.defaults.baseURL = "http://localhost:3000";
    } else if (process.env.NODE_ENV == "debug") {
    axios.defaults.baseURL = "https://www.ceshi.com";
    } else if (process.env.NODE_ENV == "production") {
    axios.defaults.baseURL = "https://www.production.com";
    }

    //修改内部http为axios
    Vue.prototype.$http = axios;
  • router\index.js中配置路由,让首页显示Home组件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import Vue from "vue";
    import Router from "vue-router";
    import Home from "@/components/Home";

    Vue.use(Router);

    export default new Router({
    // mode: 'history',
    routes: [
    { path: "/", redirect: "/home" },
    { path: "/home", name: "Home", component: Home },
    ],
    });
  • Home.vue组件,请求所有数据显示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    <template>
    <div>
    <p> 欢迎进入我的网站 </p><br>
    {{posts}}
    </div>
    </template>

    <script>
    export default {
    name: "Home",
    data(){
    return{
    posts:[]
    }
    },
    methods:{

    },
    created() {
    this.$http.get('/posts').then(res=>{
    console.log(res)
    this.posts=res.data
    })
    .catch(err=>{
    console.log(err)
    })
    }
    }
    </script>

    <style scoped>

    </style>

  • 页面可以正常显示查询的结果。

跨域说明

  • 如果是其他的服务器会出现跨域问题,json-server是支持跨域的

  • 查看响应头Access-Control-Allow-Origin: http://127.0.0.1:8080

  • 浏览器判断跨域为简单请求时候,会在Request Header中添加 Origin (协议 + 域名 + 端口)字段 , 它表示我们的请求源,CORS服务端会将该字段作为跨源标志。

  • CORS接收到此次请求后 , 首先会判断Origin是否在允许源(由服务端决定)范围之内,如果验证通过,服务端会在Response Header 添加 Access-Control-Allow-Origin、Access-Control-Allow-Credentials等字段。

    • 必须字段:
      Access-Control-Allow-Origin·:表示服务端允许的请求源,*标识任何外域,多个源,分隔

    • 可选字段
      Access-Control-Allow-Credentials: 表示是否允许发送Cookie,

      • 设置为true同时,ajax请求设置withCredentials = true,浏览器的cookie就能发送到服务端
      • 服务端设置如果是 'supportsCredentials' => false, ,表示不允许携带信息头,也会出现跨域问题

      Access-Control-Expose-Headers:调用getResponseHeader()方法时候,能从header中获 取的参数

  • 浏览器收到Respnose后会判断自己的源是否存在 Access-Control-Allow-Origin允许源中,如果不存在,会抛出“同源检测异常”。

总结:简单请求只需要CORS服务端在接受到携带Origin字段的跨域请求后,在response header中添加Access-Control-Allow-Origin等字段给浏览器做同源判断。

async 和await

  1. async作为一个关键字放在函数前边,任何一个async函数都会隐式返回一个promise;

  2. await 关键字只能在使用async定义的函数中使用,await后面可以直接跟一个Promise实例对象,await 函数不能单独使用;

  3. async/await让异步代码看起来,表现更象同代码;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 1.  async 基础用法
# 1.1 async作为一个关键字放到函数前面
async function queryData() {
# 1.2 await关键字只能在使用async定义的函数中使用 await后面可以直接跟一个 Promise实例对象
var ret = await new Promise(function(resolve, reject){
setTimeout(function(){
resolve('nihao')
},1000);
})
// console.log(ret.data)
return ret;
}
# 1.3 任何一个async函数都会隐式返回一个promise 我们可以使用then 进行链式编程
queryData().then(function(data){
console.log(data)
})

#2. async 函数处理多个异步函数
axios.defaults.baseURL = 'http://localhost:3000';

async function queryData() {
# 2.1 添加await之后 当前的await 返回结果之后才会执行后面的代码

var info = await axios.get('async1');
#2.2 让异步代码看起来、表现起来更像同步代码
var ret = await axios.get('async2?info=' + info.data);
return ret.data;
}

queryData().then(function(data){
console.log(data)
})

axios简单封装

  • 测试链接:https://api-hmugo-web.itheima.net/api/public/v1/home/floordata

  • axios.get()方法和axios.post()在提交数据时参数的书写方式还是有区别的。

    • get的第二个参数是一个{},然后这个对象的params属性值是一个参数对象的。
    • 而post的第二个参数就是一个参数对象。两者略微的区别要留意哦!
  • 封装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    import axios from "axios";

    const instance=axios.create({
    //这里是接口公共的url部分,会拼接在url参数前面
    baseURL:"https://api-hmugo-web.itheima.net/api/public/v1",
    timeout:5000,
    })


    ## 封装get请求
    /**
    * get方法,对应get请求
    * @param {String} url [请求的url地址]
    * @param {Object} params [请求时携带的参数]
    */
    import QS from 'qs';

    export function get(url, params){
    return new Promise((resolve, reject) =>{
    axios.get(url, {
    params: params
    }).then(res => {
    resolve(res.data);
    }).catch(err =>{
    reject(err.data)
    })
    });}

    ## 封装post请求
    ## post方法必须要使用对提交从参数对象进行序列化的操作,所以这里我们通过node的qs模块来序列化我们的参数。
    /**
    * post方法,对应post请求
    * @param {String} url [请求的url地址]
    * @param {Object} params [请求时携带的参数]
    */
    export function post(url, params) {
    return new Promise((resolve, reject) => {
    axios.post(url, QS.stringify(params))
    .then(res => {
    resolve(res.data);
    })
    .catch(err =>{
    reject(err.data)
    })
    });
    }

    ## 封装del请求
    export function del(url){
    return instance.get(url);
    }
    ## 封装put请求
    export function put(url,data){
    return instance.put(url,data);
    }
  • 调用

    1
    2
    3
    get("/home/floordata", {}).then((res) => {
    console.log(res);
    });

axios全局拦截

请求拦截

  • 请求发送拦截,所有的网络请求都会先走这个use方法,我们可以在它里面为请求添加一些自定义的内容

    • 比如 config 中的一些信息不符合服务器要求
    • 比如每次发送网路请求时,希望在界面显示一个请求图标
    • 某些网站请求,必须携带一些特殊的信息(token)
  • //请求发送拦截,把数据发送给后台之前做些什么......
    axios.interceptors.request.use(
      (request) => {
        //这个例子中data是loginName和password
        let REQUEST_DATA = request.data;
        //统一进行qs模块转换,将对象序列化成URL的形式,以&进行拼接。
        //JSON.stringify(ObjectDemo)是将对象转换为json字符串
        request.data = qs.stringify(REQUEST_DATA);
        //再发送给后台
        return request;
      },
      function (error) {
        // Do something with request error
        return Promise.reject(error);
      },
    );