GET请求
GET请求没有请求体,参数包含在URL中。
查询字符串
查询字符串(Query String):在URL中使用?符号将参数附加到URL末尾,多个参数之间使用&符号分隔。
js
GET /api/users?id=890418&name=Jessica HTTP/1.1
RESTful风格
RESTful风格的URL参数:将参数直接作为URL的一部分,一般用于表示资源的唯一标识符或路径参数
js
GET /api/users/890418 HTTP/1.1
数组
参数传入数组:使用相同的参数名,但允许多个值的情况
方式1:
js
GET http://localhost:8080/api/users?roleIds=1&roleIds=2 HTTP/1.1
方式2:
js
GET http://localhost:8080/users?roleIds=1,2 HTTP/1.1
方式3:
js
GET http://localhost:8080/users?roleIds[]=1&roleIds[]=2 HTTP/1.1
方式4:
js
GET http://localhost:8080/api/users?roleIds[0]=1&roleIds[1]=2 HTTP/1.1
后端get接口设计接受数组型查询参数时,只接受重复的query格式,如 arr=[1,2,3]
,那么在query里的参数格式需要是a=1&a=2&a=3
,前端get请求直接传数组会默认处理为a[]=1&a[]=2&a[]=3
,后端无法识别。
可以借助qs库,对axios请求封装paramsSerializer(params处理函数)
,是一个负责 params
序列化的函数。
js
import qs from 'qs'
qs.stringify({ a: ["b", "c", "d"] }); // a[0]=b&a[1]=c&a[2]=d
qs.stringify({ a: ["b", "c", "d"] }, { indices: false }); // a=b&a=c&a=d
// qs 还可以通过arrayFormat 选项进行格式化输出
qs.stringify({ a: ["b", "c"] }, { arrayFormat: "indices" }) // a[0]=b&a[1]=c
qs.stringify({ a: ["b", "c"] }, { arrayFormat: "brackets" }) // a[]=b&a[]=c
qs.stringify({ a: ["b", "c"] }, { arrayFormat: "repeat" }) // a=b&a=c
qs.stringify({ a: ["b", "c"] }, { arrayFormat: "comma" }) // a=b,c
js
import axios from 'axios'
axios.get({
url: '/user',
method: 'get',
baseURL: 'https://localhost:8080/api/',
// `paramsSerializer` 是一个负责 `params` 序列化的函数
paramsSerializer: paramsSerializer: (params) => qs.stringify(params, { arrayFormat: 'repeat' })
})
js
// 请求拦截器,在请求发送前格式化
axios.interceptors.request.use(async (config) => {
//只针对get方式进行序列化
if (config.method === 'get') {
config.paramsSerializer = function(params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
}
}
需要注意的是,如果请求参数中带有中括号[]
,[]
在url中属于功能性字符,前端需要使用decodeURIComponent()
函数转义,否则会出现400 Bad Request错误。
js
qs.stringify({ a: ['b', 'c', 'd'] }); // a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d
decodeURIComponent(qs.stringify({ a: ["b", "c", "d"] }) // a[0]=b&a[1]=c&a[2]=d
对象
将参数封装在一个对象中,然后将该对象作为查询字符串的值传递。
直接传一个对象作为参数是不对的,后端无法识别出来。需要把对象序列化成字符串,然后通过decodeURIComponent()
函数转义后加到url中
js
GET http://localhost:8080/users?param={"accID":"milo","field":"nick_name,email"} HTTP/1.1
js
const queryparam = {accID:"milo",field:"nick_name,email"}
// 利用JSON.stringify转化为JSON格式,再利用decodeURIComponent()方法转义。
decodeURIComponent(JSON.stringify(queryparam))
POST
JSON 数据格式
在请求的数据体中使用 JSON 格式来传递参数。application/json
作为Content-Type
的请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。
js
POST http://localhost:8080/api/users HTTP/1.1
Content-Type: application/json
{
"name": "Jessica",
"bir": 890418
}
表单数据格式
在请求的数据体中使用表单数据格式来传递参数。这是最常见的 POST 提交数据的方式,浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以application/x-www-form-urlencoded
方式提交数据。application/x-www-form-urlencoded
作为Content-Type
的请求头。
js
POST http://localhost:8080/api/users HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=hyomin&bir=890530
文件上传格式
在请求的数据体中使用多部分表单数据格式来传递参数,适用于文件上传等场景。使用表单上传文件时,必须让 form 的 enctyped 等于multipart/form-data
这个值。application/multipart/form-data
作为Content-Type
的请求头。
首先会生成一个boundary
用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后Content-Type
里指明了数据是以mutipart/form-data
来编码,本次请求的 boundary的内容在消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以--boundary
开始,紧接着内容描述信息,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary--
标示结束。
以下包含了一个文件字段 file
:file的内容是图片的二进制数据
js
POST http://localhost:8080/api/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="file"; filename="example.jpg"
Content-Type: image/jpeg
[file content(文件的二进制流)]
------WebKitFormBoundaryABC123--
以下包含一个text
字段和file
字段,text
字段的内容是字符串title
,file
字段的内容是图片的二进制流数据
js
POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA`
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--