是否可以使用 fetch API 为每个请求设置默认标头?
我想要做的是每当
Authorization
中存在 json Web 令牌时就设置一个 localStorage
标头。我当前的解决方案是使用此函数设置标题:
export default function setHeaders(headers) {
if(localStorage.jwt) {
return {
...headers,
'Authorization': `Bearer ${localStorage.jwt}`
}
} else {
return headers;
}
}
在获取请求中设置标头将如下所示:
return fetch('/someurl', {
method: 'post',
body: JSON.stringify(data),
headers: setHeaders({
'Content-Type': 'application/json'
})
})
但是必须有更好的方法来做到这一点。我目前正在开发一个 React/Redux/Express 应用程序,如果有帮助的话。
创建一个
fetch
包装器可以解决您的问题:
function updateOptions(options) {
const update = { ...options };
if (localStorage.jwt) {
update.headers = {
...update.headers,
Authorization: `Bearer ${localStorage.jwt}`,
};
}
return update;
}
export default function fetcher(url, options) {
return fetch(url, updateOptions(options));
}
如果您决定更喜欢 Axios 或其他软件包,您还可以获得额外的好处,即能够轻松地为应用程序中的所有调用切换请求客户端。您还可以执行其他操作,例如检查
options.body
是否是对象并添加 'Content-Type: application/json
标头。
Andri Möll 为 fetch
创建了一个
FetchDefaults.jsmixin,用于设置获取默认值:
var Url = require("url")
var assign = require("oolong").assign
var merge = require("oolong").merge
var PARSE_QUERY = false
var PROTOCOL_RELATIVE = true // Enable //example.com/models to mimic browsers.
exports = module.exports = function(fetch, rootUrl, defaults) {
if (typeof rootUrl === "string") rootUrl = parseUrl(rootUrl)
else defaults = rootUrl, rootUrl = null
return assign(exports.fetch.bind(null, fetch, rootUrl, defaults), fetch)
}
exports.fetch = function(fetch, rootUrl, defaults, url, opts) {
if (rootUrl != null) url = rootUrl.resolve(url)
if (typeof defaults === "function") defaults = defaults(url, opts)
return fetch(url, opts == null ? defaults : merge({}, defaults, opts))
}
function parseUrl(url) {
return Url.parse(url, PARSE_QUERY, PROTOCOL_RELATIVE)
}
根据仅 AGPL-3.0 许可证
分发您可以使用 Axios 代替 fetch,并使用拦截器
const setAuthorization = (token) => {
api.interceptors.request.use((config) => {
config.headers.Authorization = 'Bearer ' + token;
return config;
});
}
其中 Api 是带有基本 URL 的 axios 对象
const api= axios.create({
baseURL: 'http://exemple.com'
});
当您获得令牌时,您只需调用函数 setAuthorization 即可。
您可以覆盖默认的 fetch api:
var originalFetch = window.fetch;
window.fetch = function (input, init) {
if (!init) {
init = {};
}
if (!init.headers) {
init.headers = new Headers();
}
// init.headers could be:
// `A Headers object, an object literal,
// or an array of two-item arrays to set request’s headers.`
if (init.headers instanceof Headers) {
init.headers.append('MyHeader', 'Value');
} else if (init.headers instanceof Array) {
init.headers.push(['MyHeader', 'Value']);
} else {
// object ?
init.headers['MyHeader'] = 'Value';
}
return originalFetch(input, init);
};
参考资料:
一个快速但不推荐的技巧是重新定义默认的
.fetch()
函数:
const oldFetch = window.fetch;
window.fetch = function() {
arguments[1].headers = { 'blahblah' : 'blabla' };
return oldFetch.apply(window, arguments);
}
代码未经测试且未完成。如果您决定使用这个答案,请检查
arguments.length
,添加代码以保留现有标头等。我只是提供进一步探索的方向。
我不建议您覆盖全局 fetch API,如果其他库或服务依赖于 fetch,您可能会遇到问题。
制作一个获取包装器是正确的方法。 下面我假设我们想要保留所有 fetch API 行为。
因为 fetch API 的标头可以通过以下方式传递:
[['key1', 'val1'], ['key2', 'val2']]
)我们需要一个
mergeHeaders
帮手。
我将传递详细信息,但这是一个有效的实现:
function mergeHeaders (...headerInits) {
let result = {}
headerInits.forEach((init) => {
new Headers(init).forEach((value, key) => {
if (value === 'null' || value === 'undefined') {
// same as object spread: undefined overrides the current value
// 'null' and 'undefined' are not valid headers values
// therefore in this case we can remove the header
delete res[key]
} else {
// add the header
res[key] = value
}
})
})
return result
}
我们现在可以继续实现一个基本的获取器
function fetcher(input, options) {
// your headers
const defaultHeaders = { Authorization: localStorage.getItem('auth-header') }
// merge them with the headers of the options
const headers = mergeHeaders(defaultHeaders, options.headers)
// add the headers to the options
return fetch(input, { ...options, headers })
}
如果您不使用打字稿,您需要添加一些 jsdocs
jsdocs 是在底层使用 typescript lsp 的类型注释。 他们将启用自动完成
/**
* @type {typeof fetch}
*/
function fetcher(input, options) {
// your headers
const defaultHeaders = { Authorization: localStorage.getItem('auth-header') }
// merge them with the headers of the options
const headers = mergeHeaders(defaultHeaders, options.headers)
// add the headers to the options
return fetch(input, { ...options, headers })
}
我们开始了,我们有一个带有默认标头的获取器!
如果您的用例开始变得更加复杂,请考虑使用库。 我最近发布了我的 fetch API 配置库,名为 up-fetch
这是一个使用 up-fetch
的快速示例const fetcher = up(fetch, () => ({
headers: { Authorization: localStorage.getItem('auth-header') }
}))
结果相同,只是自动解析响应,如果
response.ok
是 false
,则会抛出错误。
还有更多功能,例如参数作为对象、baseUrl 配置、验证适配器、拦截器...
希望有帮助