Ajax(Asynchronous JavaScript and XML)
是一种前端技术,通过使用 JavaScript
进行异步请求,并在无需刷新整个页面的情况下更新页面内容。它可以使用原生的 XMLHttpRequest
对象或其他封装库(如 jQuery
的 $.ajax
)来实现。Ajax
可以发送和接收各种数据格式,例如 XML、JSON 或 HTML。
Axios
是一个基于 Promise
的现代 HTTP
客户端,用于在浏览器和 Node.js
中发送 HTTP
请求。它更简单、更具可读性,并且提供了更多的功能,如拦截请求和响应、请求取消、自动转换JSON
的响应数据等。Axios
提供了类似于 Ajax
的 API
,并且广泛应用于 Vue、React
等框架和库中。
Fetch
是 JavaScript
提供的现代 API
,用于发送 HTTP
请求。它是基于 Promise
设计的,提供了更简洁的用法和更强大的功能,如请求和响应对象的直观性、对请求和响应进行拦截、更好的错误处理、基于流的请求和响应等。Fetch API
是浏览器内置的标准 API
,不需要额外的库或框架。与XMLHttpRequest
不同的是,fetch默认情况下不会将跨域Cookie
发送到服务器,并且遇到400或500
级别的Http
响应代码不会抛出错误,需要手动检查响应状况。Ajax
是一种技术概念,可以使用原生的 XMLHttpRequest
或其他封装库实现异步请求。而 Axios
和 Fetch
都是库或 API
,提供了更便捷的方式来发送 HTTP
请求。Axios
和 Fetch
都是基于 Promise
的,使用起来更符合现代 JavaScript
的异步编程风格,可以更轻松地处理异步操作。Axios
提供了更多的功能,如请求拦截、响应拦截、请求取消等,而 Fetch
的功能相对更基础,可以通过其他库(如拦截器库)实现类似的功能。
ajax
Fetch
是浏览器原生支持的 API
,不需要额外的库,但它的兼容性不如 Axios
,某些较旧的浏览器可能不支持或需要使用 polyfill
。Ajax
和 Axios
都支持在浏览器和 Node.js
环境中使用,而 Fetch 的主要用途是在浏览器中进行前端开发。
总的来说,Axios
和 Fetch
提供了更现代和便捷的方式来发送 HTTP
请求,具有更好的可读性和功能。如果需要更丰富的功能和更好的兼容性,可以选择使用 Axios
;如果只需基础的请求功能且希望依赖更少的第三方库,可以考虑使用 Fetch
。
fetch
Fetch API 是近年来被提及将要取代XHR的技术新标准,是一个 HTML5 的 API。 Fetch 并不是XHR的升级版本,而是从一个全新的角度来思考的一种设计。
Fetch 是基于 Promise 语法结构,而且它的设计足够低阶,这表示它可以在实际需求中进行更多的弹性设计。对于XHR所提供的能力来说,Fetch 已经足够取代XHR,并且提供了更多拓展的可能性。
// 获取 some.json 资源
fetch('some.json')
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log('data', data);
})
.catch(function(error) {
console.log('Fetch Error: ', error);
});
// 采用ES2016的 async/await 语法
async function() {
try {
const response = await fetch('some.json');
const data = response.json();
console.log('data', data);
} catch (error) {
console.log('Fetch Error: ', error)
}
}
fetch.Post请求
fetch('https://www.api.com/api/xxx', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: 'a=1&b=2',
}).then(resp => resp.json()).then(resp => {
console.log(resp)
});
fetch.Get请求
fetch('https://www.api.com/api/xxx?location=北京&key=bc08513d63c749aab3761f77d74fe820',{
method:'GET'
}) // 返回一个Promise对象
.then((res)=>{
return res.json();
})
.then((res)=>{
console.log(res) // res是最终的结果
})
fetch请求网页
fetch('https://www.api.com/api/xxx')
.then(response => response.text())
.then(data => console.log(data));
自定义header
var headers = new Headers({
"Content-Type": "text/plain",
"X-Custom-Header": "aaabbbccc",
});
var formData = new FormData();
formData.append('name', 'lxa');
formData.append('file', someFile);
var config = {
credentials: 'include', // 支持cookie
headers: headers, // 自定义头部
method: 'POST', // post方式请求
body: formData // post请求携带的内容
};
fetch('https://www.api.com/api/xxx', config)
.then(response => response.json())
.then(data => console.log(data));
// 或者这样添加头部
var content = "Hello World";
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");
fetch其他参数
- method: 请求的方法,例如:GET,POST。
- headers: 请求头部信息,可以是一个简单的对象,也可以是 Headers 类实例化的一个对象。
- body: 需要发送的信息内容,可以是Blob,BufferSource,FormData,URLSearchParams或者USVString。注意,GET,HEAD方法不能包含body。
- mode: 请求模式,分别有cors,no-cors,same-origin,navigate这几个可选值。
- cors: 允许跨域,要求响应中Acess-Control-Allow-Origin这样的头部表示允许跨域。
- no-cors: 只允许使用HEAD,GET,POST方法。
- same-origin: 只允许同源请求,否则直接报错。
- navigate: 支持页面导航。
- credentials: 表示是否发送cookie,有三个选项
- omit: 不发送cookie。
- same-origin: 仅在同源时发送cookie。
- include: 发送cookie。
- cache: 表示处理缓存的策略。
- redirect: 表示发生重定向时,有三个选项
- follow: 跟随。
- error: 发生错误。
- manual: 需要用户手动跟随。
- integrity: 包含一个用于验证资资源完整性的字符串
var URL = 'https://www.api.com/api/xxx';
// 实例化 Headers
var headers = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
var getReq = new Request(URL, {method: 'GET', headers: headers });
fetch(getReq).then(function(response) {
return response.json();
}).catch(function(error) {
console.log('Fetch Error: ', error);
});
fetch的取消请求
const controller = new AbortController()
const signal = controller.signal()
fetch(url,{signal}).then()then().catch()
controller.abort()// 停止fetch请求
fetch跟xhr比较的优点是什么
fetch 和 XMLHttpRequest(XHR)是用于在 JavaScript 中进行网络请求的两种主要方式。它们各自有一些优点和特点。
fetch 的优点包括:
- Promise 构建: 使用 Promise 对象进行构建,简洁清晰。能够更好地处理异步操作和链式调用,代码结构更清晰。
- 更强大的 Response 对象: fetch 返回的 Response 对象更加强大和灵活,可以轻松处理 JSON 数据、文本、Blob、FormData 等形式的数据。
- 使用简单: 使用 fetch 发起请求可以更加简单明了,代码量更少。
- 更加现代: fetch 更加现代化,原生支持 Promise、async/await 等新特性,更符合现代 JavaScript 开发的趋势。
- 更灵活的配置: fetch 提供了更灵活的请求配置选项,能够方便地进行跨域请求设置、请求头自定义等操作。
然而,也需要注意 fetch 的一些缺点,比如对旧版浏览器的兼容性以及对请求状态(比如请求取消)的处理不如 XHR 灵活等问题。
相比之下,XMLHttpRequest(XHR)的优点包括:
- 兼容性: XHR 是传统的方式,几乎所有的浏览器都支持,对于老旧浏览器兼容性更好。
- 功能丰富: XHR 有一些高级功能如上传和下载进度的监听、处理超时等,这些功能在 fetch 中可能需要额外处理。
- 跨域请求: 在一些特定情况下(比如旧版 IE 的 CORS 支持),XHR 可能更容易处理一些跨域请求的情况。
总的来说,fetch 在现代 JavaScript 开发中更受欢迎,由于其简洁的 API 设计、Promise 支持以及更加现代化的特性,但在一些特定情况下,比如对于老旧浏览器的兼容性要求或者对于一些特殊的请求需求,可能需要使用 XHR。
取消请求AbortController(axios,v0.22.0+)
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {});
// cancel the request
controller.abort()
取消请求cancalToken (axios,v0.22.0)
<template>
<div>
<p v-if="loading">Loading...</p>
<p v-else>{{ data }}</p>
<button @click="fetchData">Fetch Data</button>
<button @click="cancelRequest">取消请求</button>
</div>
</template>
<script>
import axiosInstance from './axiosInstance';
export default {
data() {
return {
loading: false,
data: null,
source: axiosInstance.CancelToken.source()
};
},
methods: {
async fetchData() {
try {
this.loading = true;
const response = await axiosInstance.get('/api/some-endpoint', {
cancelToken: this.source.token
});
this.data = response.data;
this.loading = false;
} catch (error) {
if (axiosInstance.isCancel(error)) {
console.log('请求被取消:', error.message);
} else {
// 处理其他错误
}
this.loading = false;
}
},
cancelRequest() {
this.source.cancel('请求被用户取消');
}
}
};
</script>
import React, { useState } from 'react';
import axiosInstance from './axiosInstance';
function YourComponent() {
const [loading, setLoading] = useState(false);
const [data, setData] = useState(null);
const source = axiosInstance.CancelToken.source();
const fetchData = async () => {
try {
setLoading(true);
const response = await axiosInstance.get('/api/some-endpoint', {
cancelToken: source.token
});
setData(response.data);
setLoading(false);
} catch (error) {
if (axiosInstance.isCancel(error)) {
console.log('请求被取消:', error.message);
} else {
// 处理其他错误
}
setLoading(false);
}
};
const cancelRequest = () => {
source.cancel('请求被用户取消');
};
return (
<div>
{loading ? <p>Loading...</p> : <p>{data}</p>}
<button onClick={fetchData}>Fetch Data</button>
<button onClick={cancelRequest}>取消请求</button>
</div>
);
}
export default YourComponent;
get请求
// 为给定 ID 的 user 创建请求
axios
.get("/user?ID=12345")
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 上面的请求也可以这样做
axios
.get("/user", {
params: {
ID: 12345,
},
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 发送 GET 请求(默认的方法)
axios("/user/12345");
post请求
axios
.post("/user", {
firstName: "Fred",
lastName: "Flintstone",
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 发送 POST 请求
axios({
method: "post",
url: "/user/12345",
data: {
firstName: "Fred",
lastName: "Flintstone",
},
});
请求及响应配置
const obj = {
url: "/user",
method: "get", // default
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: "https://some-domain.com/api/",
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [
function (data, headers) {
// 对 data 进行任意转换处理
return data;
},
],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [
function (data) {
// 对 data 进行任意转换处理
return data;
},
],
// `headers` 是即将被发送的自定义请求头
headers: { "X-Requested-With": "XMLHttpRequest" },
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345,
},
// `paramsSerializer` 是一个负责 `params` 序列化的函数
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, { arrayFormat: "brackets" });
},
// `data` 是作为请求主体被发送的数据
// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data: {
firstName: "Fred",
},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout: 1000,
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false, // default
// `adapter` 允许自定义处理请求,以使测试更轻松
// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
auth: {
username: "janedoe",
password: "s00pers3cret",
},
// `responseType` 表示服务器响应的数据类型,
// 可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: "json", // default
// `responseEncoding` indicates encoding to use for decoding responses
// Note: Ignored for `responseType` of 'stream' or client-side requests
responseEncoding: "utf8", // default
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
xsrfCookieName: "XSRF-TOKEN", // default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: "X-XSRF-TOKEN", // default
// `onUploadProgress` 允许为上传处理进度事件
onUploadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},
// `onDownloadProgress` 允许为下载处理进度事件
onDownloadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `maxContentLength` 定义允许的响应内容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。
// 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve;
// 否则,promise 将被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},
// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
// 如果设置为0,将不会 follow 任何重定向
maxRedirects: 5, // default
// `socketPath` defines a UNIX Socket to be used in node.js.
// e.g. '/var/run/docker.sock' to send requests to the docker daemon.
// Only either `socketPath` or `proxy` can be specified.
// If both are specified, `socketPath` is used.
socketPath: null, // default
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。
//允许像这样配置选项:
// `keepAlive` 默认没有启用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// 'proxy' 定义代理服务器的主机名称和端口
// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
// 这将会设置一个 `Proxy-Authorization` 头,
// 覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
proxy: {
host: "127.0.0.1",
port: 9000,
auth: {
username: "mikeymike",
password: "rapunz3l",
},
},
// `cancelToken` 指定用于取消请求的 cancel token
// (查看后面的 Cancellation 这节了解更多)
cancelToken: new CancelToken(function (cancel) {}),
};
响应结构
const obj = {
// `data` 由服务器提供的响应
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: "OK",
// `headers` 服务器响应的头
headers: {},
// `config` 是为请求提供的配置信息
config: {},
// 'request'
// `request` is the request that generated this response
// It is the last ClientRequest instance in node.js (in redirects)
// and an XMLHttpRequest instance the browser
request: {},
};
响应参数
axios.get("/user/12345").then(function (response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
});
拦截器
在请求或响应被 then
或 catch
处理前拦截它们
// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
return config;
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error);
}
);
// 添加响应拦截器
axios.interceptors.response.use(
function (response) {
// 对响应数据做点什么
return response;
},
function (error) {
// 对响应错误做点什么
return Promise.reject(error);
}
);
如果你想在稍后移除拦截器,可以这样:
const myInterceptor = axios.interceptors.request.use(function () {});
axios.interceptors.request.eject(myInterceptor);
可以为自定义 axios
实例添加拦截器
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
axios
的拦截器通常在以下场景中使用:
- 身份验证:可以在请求前配置拦截器,用于在每个请求中添加身份验证标头。这样可以确保在发送请求之前,用户已经通过身份验证。
- 错误处理:拦截器可以用于处理请求发生错误的情况。例如,当收到错误响应时,可以通过拦截器来处理特定的错误状态码,并在应用程序中进行适当的处理。
- 请求和响应转换:拦截器可以用于在发送请求之前和接收响应之后,对请求和响应进行转换。例如,可以在请求发送时,将请求数据转换为特定格式,或者在接收响应时,将响应数据进行解析和转换。
- 缓存处理:拦截器可以用于在发送请求之前,检查是否存在缓存数据。如果存在缓存数据,可以通过拦截器直接返回缓存数据,而不需要发送实际的请求。
- 请求重试:拦截器可以用于在请求失败时进行重试。例如,当请求超时或服务器错误时,可以通过拦截器设置重试策略,并自动进行请求重试。
这些只是一些常见的使用场景,实际上,拦截器非常灵活,可以根据需要进行自定义配置,以满足特定的业务需求。
错误处理
axios.get("/user/12345").catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log("Error", error.message);
}
console.log(error.config);
});
可以使用 validateStatus
配置选项定义一个自定义 HTTP
状态码的错误范围。
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // Reject only if the status code is greater than or equal to 500
}
})
axios 批量发送请求
<body>
<button id="btn1">点我获取测试数据</button>
<script>
const btn1 = document.getElementById('btn1');
btn1.onclick = async () => {
axios.all([
axios.get('http://localhost:5000/test1'),
axios.get('http://localhost:5000/test2'),
axios.get('http://localhost:5000/test3'),
]).then(
response =>{console.log(response);},
error =>{console.log(error);}
)
};
</script>
</body>
解释:Axios.all( ) 基于 promise.all( ),所有的都是成功的回调才会返回数据,如果有一个失败的回调,就会走错误信息。此方法会按顺序打印 并发的三个请求的数据,并且如果用了延迟请求也会是原本的顺序,这是 axios 封装好的。
常规用法
import axios from 'axios';
axios.get('/user?ID=12345') // 二选一,传参方式
axios.get( '/user', {params: {}} )
.then(function (res) {})
.catch(function (e) {)
.finally(function () {});
async function getUser() {
try {
const res = await axios.get('/user?ID=12345');
} catch (e) {}
}
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
Promise.all([getUserAccount(), getUserPermissions()])
.then(function (results) { // 执行多个并发请求
const acct = results[0];
const perm = results[1];
});
// Send a POST request
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
// GET request for remote image in node.js
axios({
method: 'get',
url: 'https://bit.ly/2mTM3nY',
responseType: 'stream'
})
.then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
axios['post'](
portfolioTrialUrl + 'pms/simularDeal/importNew',
params,
{ timeout: 24 * 60 * 60 * 1000 }// 超时时间
)
axios.all([
axios.get('/api/users'),
axios.get('/api/products')
]).then(axios.spread(function (usersResponse, productsResponse) {
// 处理 usersResponse 和 productsResponse
})).catch(function (error) {
// 处理错误
});
axios.all([
axios.get('/api/users'),
axios.get('/api/products')
]).then(axios.spread(function (usersResponse, productsResponse) {
// 处理 usersResponse 和 productsResponse
})).catch(function (error) {
// 处理错误
});
全局配置
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
自定义配置
const instance = axios.create({
baseURL: 'https://api.example.com'
});
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
非常规用法
拦截器
axios.interceptors.request.use(function (config) {
return config;
}, function (error) {
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
return Promise.reject(error);
});
如果以后需要删除拦截器,可以这样。
const k = axios.interceptors.request.use(function () {});
axios.interceptors.request.eject(k);
您还可以清除请求或响应的所有拦截器。
const instance = axios.create();
instance.interceptors.request.use(function () {});
instance.interceptors.request.clear(); // Removes interceptors from requests
instance.interceptors.response.use(function () {});
instance.interceptors.response.clear(); // Removes interceptors from responses
取消请求AbortController(v0.22.0+)
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {});
// cancel the request
controller.abort()
下面CancelToken is deprecated since v0.22.0
<body>
<button id="btn1">点我获取测试数据</button>
<script>
const btn1 = document.getElementById('btn1');
const { CancelToken, isCancel } = axios // CancelToken能为一次请求‘打标识’
let cancel;
btn1.onclick = async () => {
if(cancel) cancel();//避免多次反复请求
axios({
url: 'http://localhost:5000/test1?delay=3000',
cancelToken: new CancelToken((c) => { //c是一个函数,调用c就可以关闭本次请求
cancel = c;
})
}).then(
response => { console.log('成功了', response); },
error => {
if (isCancel(error)) {
//如果进入判断,证明:是用户取消了请求
console.log('用户取消了请求,原因是', error.message);
} else {
console.log('失败了', error);
}
}
)
}
</script>
</body>
原理
使用原生的 XMLHttpRequest
对象时,可以通过调用其 abort()
方法来取消已经建立的请求。abort()
方法会立即中断请求,并触发 onabort
事件。
以下是取消 XMLHttpRequest
请求的基本步骤:
- 创建一个
XMLHttpRequest
对象。 - 通过
open()
方法设置请求的方法、URL 等参数。 - (可选) 设置请求头部信息。
- (可选) 监听请求的不同事件,如请求成功、失败等。
- 发送请求,调用
send()
方法。 - 当需要取消请求时,调用
abort()
方法。
例如,以下是一个使用原生 XMLHttpRequest
对象发送请求并取消的示例代码:
// 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 设置请求的方法和 URL
xhr.open('GET', 'https://example.com/api', true);
// 监听请求成功和失败的事件
xhr.onload = function() {
// 请求成功的处理逻辑
console.log(xhr.responseText);
};
xhr.onerror = function() {
// 请求失败的处理逻辑
console.log('Request failed!');
};
// 发送请求
xhr.send();
// 取消请求
xhr.abort();
在上面的代码中,调用 xhr.abort()
方法会取消请求,并触发 onabort
事件,以便开发者可以处理取消请求的逻辑。需要注意的是,已经发送出去的请求可能无法完全被取消,具体是否能够取消请求取决于服务器的实现和网络状态。因此,及时取消请求是一种良好的实践,可以减少不必要的请求和资源浪费。
http包是如何创建一个网络请求的,又是如何取消一个网络请求的
在 Node.js 中,可以使用内置的 http
模块来创建网络请求。
创建一个网络请求的基本步骤如下:
- 引入
http
模块:const http = require('http');
- 创建一个 HTTP 请求的配置对象。
- 使用
http.request()
方法创建一个 HTTP 请求对象。 - 监听请求的事件,比如
response
事件。 - 发送请求,使用
request.end()
方法。
以下是一个使用 http
模块创建网络请求的示例代码:
const http = require('http');
// 创建请求的配置对象
const options = {
hostname: 'example.com',
port: 80,
path: '/api',
method: 'GET'
};
// 创建 HTTP 请求对象
const request = http.request(options, (response) => {
let data = '';
// 监听响应的数据事件
response.on('data', (chunk) => {
data += chunk;
});
// 监听响应结束事件
response.on('end', () => {
console.log(data);
});
});
// 发送请求
request.end();
当需要取消一个网络请求时,http
模块并没有提供直接取消的方法。但可以通过触发 request.abort()
方法来实现中断请求的效果。request.abort()
方法会使底层的请求立即中断,并触发 abort
事件。
以下是一个示例代码,演示如何取消一个网络请求:
const http = require('http');
const options = {
hostname: 'example.com',
port: 80,
path: '/api',
method: 'GET'
};
// 创建请求
const request = http.request(options, (response) => {
// 请求成功的处理逻辑
});
// 监听取消请求的事件
request.on('abort', () => {
// 取消请求的处理逻辑
console.log('Request aborted!');
});
// 发送请求
request.end();
// 取消请求
request.abort();
通过调用 request.abort()
方法,会触发 abort
事件,从而可以捕获并处理取消请求的逻辑。请注意,已经发送出去的请求可能无法完全被取消,具体是否能够取消请求取决于服务器的实现和网络状态。因此,及时取消请求是一种良好的实践,可以减少不必要的请求和资源浪费。
node的http模块的底层原理是什么
Node.js 的 http
模块是建立在核心模块 net
上的。net
模块提供了底层的网络通信功能,而 http
模块则在其基础上实现了 HTTP 协议相关的功能。
底层的原理如下:
- 创建服务端:使用
net.createServer()
方法创建一个 TCP 服务器,并监听指定的端口。 - 接受连接请求:当有客户端连接到服务器时,
net
模块会触发connection
事件,并返回一个socket
对象,代表与客户端的连接。 - HTTP 解析:
http
模块会解析来自客户端的 HTTP 请求,包括请求行、请求头和请求体等信息。它会根据解析的结果构建一个http.IncomingMessage
对象,包含了解析后的请求信息。 - 处理请求:服务器可以通过监听
request
事件来处理客户端的请求。当请求被完全接收后,http
模块会触发request
事件,并传递一个http.IncomingMessage
对象和一个http.ServerResponse
对象作为参数。http.ServerResponse
对象用于向客户端发送响应。 - HTTP 响应:服务器使用
http.ServerResponse
对象来构建并发送 HTTP 响应给客户端。它提供了一系列的方法,如writeHead()
设置响应头、write()
发送响应体、end()
结束响应等。 - 关闭连接:当客户端完成请求并接收到响应后,TCP 连接可以通过调用
socket.end()
或socket.destroy()
方法来关闭。
总结来说,http
模块的底层原理是通过 net
模块建立 TCP 服务器,接收客户端连接并解析 HTTP 请求,然后通过 http.ServerResponse
对象构建并发送 HTTP 响应。这样实现了基于 HTTP 协议的网络通信功能。
websocket底层是如何实现的,他跟http比较会有性能问题吗?会有兼容问题吗?
WebSocket 是一种在单个 TCP 连接上实现全双工通信的协议,它与 HTTP 协议相比具有不同的实现方式和特点。
底层实现方式:
- 建立连接:WebSocket 客户端通过发送 HTTP 请求(包含 Upgrade 头部)给服务器来升级连接为 WebSocket。
- 握手:服务器接受升级请求后,返回 101 状态码表示连接已升级为 WebSocket。此后,基于单个 TCP 连接,客户端和服务器之间将保持一个持久的双向通信通道。
- 数据传输:WebSocket 使用帧(frame)来划分数据包,确保消息的完整性和顺序。这些帧可以以二进制格式或文本格式传输。
- 断开连接:WebSocket 连接可以显式关闭,或者在网络断开或发生异常时自动关闭。
相对于传统的 HTTP 请求-响应模式,WebSocket 具有以下优点:
- 实时性:由于 WebSocket 的双向通信特性,服务器可以主动向客户端推送实时数据,而不需要客户端再次发送请求。
- 减少延迟:WebSocket 建立在长连接上,避免了重复的握手过程,减少了通信开销和延迟。
- 较少的带宽消耗:WebSocket 的连接协议头相对较小,并且它使用二进制帧和压缩等技术,可以减少数据传输的大小。
性能问题:
相比于 HTTP,WebSocket 可以通过减少握手和通信开销等方式提高性能。它更适合需要实时数据传输和频繁通信的场景。
兼容性问题:
WebSocket 是 HTML5 中的新增技术,现代浏览器(如 Chrome、Firefox、Safari、Edge 等)都支持 WebSocket。对于不支持 WebSocket 的浏览器,可以使用一些库或框架来模拟 WebSocket 的功能,如利用长轮询或 SSE(Server-Sent Events)。
总结来说,WebSocket 通过建立持久连接和双向通信的方式,提供了实时性和较低的延迟,相比传统的 HTTP 请求-响应模式更适合实时通信场景。而且现代浏览器对 WebSocket 有良好的支持,但需要考虑向下兼容的问题,对不支持 WebSocket 的浏览器要做适当处理。
websocket的性能比http好,为什么大家还是更加愿意用http呢?
虽然 WebSocket
在一些方面具有性能优势,但为什么大家还是更倾向于使用 HTTP
呢?主要有以下几点原因:
- 历史原因:
HTTP
是Web
开发的基础,长期以来被广泛应用于传输网页和静态资源。较早的Web
应用主要是基于HTTP
的请求-响应模式实现的,形成了习惯和惯例。 - 客户端支持:所有主流浏览器都内置了对
HTTP
协议的支持,而WebSocket
的支持并不是那么普遍。在某些特定的使用环境中,可能出于兼容性考虑而选择使用HTTP
。 - 安全性考虑:当需要保护数据安全时,
HTTP
的特点是每次请求都会进行全面的身份验证和授权。而对于WebSocket
来说,建立之后就可以保持持久连接,可能需要额外的安全措施来确保连接的安全性。 - 现有基础设施:很多现有的基础设施,如负载均衡、反向代理等,更易于与基于
HTTP
的应用集成。WebSocket
的使用可能会需要一些额外的配置和调整,会增加一些部署和维护的复杂性。 - 需求场景不同:
WebSocket
更适用于实时性要求较高的应用场景,如即时聊天、实时推送等。而对于一些传统的请求-响应模式的应用,如阅读文章、浏览网页等,HTTP
已经足够满足需求。
综上所述,尽管 WebSocket
在一些性能方面有优势,但由于历史原因、客户端支持、安全性考虑、现有基础设施以及需求场景等因素的影响,HTTP
仍然是更广泛使用的协议。在实际应用中,需要根据具体需求和场景来选择使用适当的协议。
axios源码有两种创建服务的方法,一个是http一个是xhr,他们是如恶化选择的。
Axios
是一个基于 Promise
的 HTTP
请求客户端,它默认使用 XMLHttpRequest(XHR)
来发送请求。XHR
是浏览器提供的内置 API
,用于在前端发起 HTTP
请求。
在使用 Axios 发送请求时,并没有直接通过参数来选择请求方式(XHR 或者 HTTP)。Axios 默认使用 XHR 进行请求,但它也提供了对其他底层库(如 http/https)的支持。
在浏览器环境下,Axios 会使用 XHR,主要由以下几个原因:
- XHR 的广泛支持:几乎所有现代浏览器都支持 XHR,因此在大多数情况下,XHR 是一个可靠且被广泛使用的底层实现。
- 功能强大:XHR 提供了一系列功能,如跨域支持、请求中断、进度监测等。Axios 封装了 XHR,使其更易于使用,并提供了丰富的配置选项。
当在服务器端运行时,例如在 Node.js 环境下,Axios 可以使用 http 或 https 库作为底层实现,以发起 HTTP 请求。
根据需求选择库或底层实现方式时,要考虑以下因素:
- 客户端支持:如果需要在浏览器中运行,XHR 是首选选项,因为它具有良好的支持。
- 功能要求:根据具体功能要求选择底层实现方式,如是否需要支持跨域、进度监测等。
因此,在使用 Axios 时,底层使用的是 XHR,而选择底层实现方式的具体逻辑由 Axios 内部进行处理,不是通过传递参数的方式来进行选择的。
axios拦截器实现原理剖析
Axios 是一个基于 Promise 的 HTTP 客户端,广泛用于浏览器和 Node.js 环境。它的拦截器功能允许开发者在发送请求或接收响应前对它们进行拦截和处理。这样的设计使得开发者可以在请求发送前或响应返回后执行特定逻辑,例如修改请求头、统一处理错误等。下面是 Axios 拦截器的简要实现原理剖析:
- Axios 实例化:Axios 在使用前需要通过实例化来创建一个 Axios 实例。这个 Axios 实例拥有一系列方法用于发送各种类型的请求。
- 注册拦截器:使用 Axios 实例的
interceptors
对象,开发者可以通过use
方法注册请求拦截器和响应拦截器。请求拦截器用于在请求发送前执行逻辑,响应拦截器用于在接收响应后执行逻辑。 - 拦截器队列:Axios 内部维护了一个拦截器队列,用于存储请求拦截器和响应拦截器。当发起请求时,Axios 会按照注册顺序依次执行请求拦截器,发送请求,然后依次执行响应拦截器。
- 执行逻辑:在执行拦截器时,开发者可以修改配置、添加请求头、处理错误等。对于请求拦截器,也可以返回一个新的配置对象或 Promise 对象来中断请求或修改请求行为。对于响应拦截器,可以处理响应数据、统一处理错误等。
总的来说,Axios 的拦截器实现原理是通过利用拦截器队列,按照注册顺序执行请求拦截器和响应拦截器,并允许开发者在执行过程中干预请求和响应,从而实现请求和响应的拦截和处理。
应用场景 请求拦截器用于在接口请求之前做的处理,比如为每个请求带上相应的参数(token,时间戳等)。 返回拦截器用于在接口返回之后做的处理,比如对返回的状态进行判断(token是否过期)。
拦截器的使用
- 在
src
目录下建立api
文件夹 - 文件夹内建立
axios.js
文件,进行接口请求的初始化配置
import axios from 'axios'
let instance = axios.create({
baseURL: "http://localhost:3000/",
headers: {
'content-type': 'application/x-www-form-urlencoded'
}
})
//请求拦截器
instance.interceptors.request.use(config => { //拦截请求,做统一处理
const token = "asdasdk"
//在每个http header都加上token
config.headers.authorization = token
return config
}, err => {//失败
return Promise.reject(err)
})
//响应拦截器
instance.interceptors.response.use(response => { //拦截响应,做统一处理
if (response.data.code) {
switch (response.data.code) {
case 200:
console.log("1111")
}
}
return response
}, err => { //无响应时的处理
return Promise.reject(err.response.status)
})
export default instance
在main.js中引入,并将其绑定到Vue原型上,设为全局,不用在每个页面重新引入
import instance from './api/axios'
Vue.prototype.$http = instance
页面使用
this.$http.get(url).then(r => console.log(r)).catch(err => console.log(err))
this.$http.post(url, params).then(r => console.log(r)).catch(err => console.log(err))
效果展示
axios拦截器实现原理剖析
axios接口请求内部流程
axios原理简化
function Axios(){
this.interceptors = {
//两个拦截器
request: new interceptorsManner(),
response: new interceptorsManner()
}
}
//真正的请求
Axios.prototype.request = function(){
let chain = [dispatchRequest, undefined];//这儿的undefined是为了补位,因为拦截器的返回有两个
let promise = Promise.resolve();
//将两个拦截器中的回调加入到chain数组中
this.interceptors.request.handler.forEach((interceptor)=>{
chain.unshift(interceptor.fulfilled, interceptor.rejected);
})
this.interceptors.response.handler.forEach((interceptor)=>{
chain.push(interceptor.fulfilled, interceptor.rejected);
})
while(chain.length){
//promise.then的链式调用,下一个then中的chain为上一个中的返回值,每次会减去两个
//这样就实现了在请求的时候,先去调用请求拦截器的内容,再去请求接口,返回之后再去执行响应拦截器的内容
promise = promise.then(chain.shift(),chain.shift());
}
}
function interceptorsManner(){
this.handler = [];
}
interceptorsManner.prototype.use = function(fulfilled,rejected){
//将成功与失败的回调push到handler中
this.handler.push({
fulfilled: fulfilled,
rejected: rejected
})
}
//类似方法批量注册,实现多种请求
util.forEach(["get","post","delete"],(methods)=>{
Axios.prototype[methods] = function(url,config){
return this.request(util.merge(config||{},{//合并
method: methods,
url: url
}))
}
})