Handling Request Headers
# Handling Request Headers
# Requirements Analysis
We left a problem from the previous lesson:
axios({
method: 'post',
url: '/base/post',
data: {
a: 1,
b: 2
}
})
2
3
4
5
6
7
8
We handled the request data by converting data to a JSON string, but when the data is sent to the server, the server can't properly parse our data because we didn't set the correct Content-Type in the request header.
So first, we need to support configuring the headers property when sending requests:
axios({
method: 'post',
url: '/base/post',
headers: {
'content-type': 'application/json;charset=utf-8'
},
data: {
a: 1,
b: 2
}
})
2
3
4
5
6
7
8
9
10
11
Additionally, when the data we pass is a plain object and headers doesn't have a Content-Type property configured, we need to automatically set the request header's Content-Type field to application/json;charset=utf-8.
# Implementing the processHeaders Function
Based on the requirements, we need to implement a utility function to process the headers in the request. We create a new file headers.ts in the helpers directory.
helpers/headers.ts:
import { isPlainObject } from './util'
function normalizeHeaderName (headers: any, normalizedName: string): void {
if (!headers) {
return
}
Object.keys(headers).forEach(name => {
if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
headers[normalizedName] = headers[name]
delete headers[name]
}
})
}
export function processHeaders (headers: any, data: any): any {
normalizeHeaderName(headers, 'Content-Type')
if (isPlainObject(data)) {
if (headers && !headers['Content-Type']) {
headers['Content-Type'] = 'application/json;charset=utf-8'
}
}
return headers
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
An important note here: request header property names are case-insensitive. For example, in our earlier example, the header property name content-type was all lowercase, so we first need to normalize some header property names.
# Implementing Request Header Processing Logic
Before that, let's modify the AxiosRequestConfig interface type definition to add the optional headers property:
types/index.ts
export interface AxiosRequestConfig {
url: string
method?: Method
data?: any
params?: any
headers?: any
}
2
3
4
5
6
7
index.ts:
function processConfig (config: AxiosRequestConfig): void {
config.url = transformURL(config)
config.headers = transformHeaders(config)
config.data = transformRequestData(config)
}
function transformHeaders (config: AxiosRequestConfig) {
const { headers = {}, data } = config
return processHeaders(headers, data)
}
2
3
4
5
6
7
8
9
10
Since header processing depends on data, we must process request headers before processing request body data.
xhr.ts:
export default function xhr (config: AxiosRequestConfig): void {
const { data = null, url, method = 'get', headers } = config
const request = new XMLHttpRequest()
request.open(method.toUpperCase(), url, true)
Object.keys(headers).forEach((name) => {
if (data === null && name.toLowerCase() === 'content-type') {
delete headers[name]
} else {
request.setRequestHeader(name, headers[name])
}
})
request.send(data)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
We need an extra check here: when data is empty, configuring Content-Type in the request header is meaningless, so we remove it.
# Writing the Demo
axios({
method: 'post',
url: '/base/post',
data: {
a: 1,
b: 2
}
})
axios({
method: 'post',
url: '/base/post',
headers: {
'content-type': 'application/json;'
},
data: {
a: 1,
b: 2
}
})
const paramsString = 'q=URLUtils.searchParams&topic=api'
const searchParams = new URLSearchParams(paramsString)
axios({
method: 'post',
url: '/base/post',
data: searchParams
})
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
Through the demo, we can see that when request data is a plain object and headers isn't configured, Content-Type:application/json;charset=utf-8 is automatically added. We also notice that when data is of certain types like URLSearchParams, the browser automatically adds an appropriate Content-Type to the request header.
This concludes our request processing logic for now. Currently, our requests can receive server responses at the network level. In the next lesson, we'll handle server responses at the code level and allow callers to access the data returned from the server.