4.2、浏览器请求详解(ajax、fetch、axios使用,手写ajax)

浏览器请求详解

  • 1.ajax
    • 手写ajax
  • 2. fetch
    • 2.1 Response
    • 2.2 定制 HTTP 请求
    • 2.3 option API
    • 2.4 fetch cancel
  • 3.axios
    • 3.1 基本使用
    • 3.2 响应数据
    • 3.3 创建实例(封装)
    • 3.4 拦截器
    • 3.5 完整的请求配置
  • 总结

在浏览器端发送网络请求的常见方式:

  1. ajax;
  2. fetch;
  3. axios;

1.ajax

Ajax 是一个技术统称,是一个概念模型,它囊括了很多技术,并不特指某一技术,它很重要的特性之一就是让页面实现局部刷新。
特点:

  • 局部刷新页面,无需重载整个页面。

简单来说,Ajax 是一种思想,XMLHttpRequest 只是实现 Ajax 的一种方式。其中 XMLHttpRequest 模块就是实现 Ajax 的一种很好的方式。

手写ajax

利用 XMLHttpRequest 模块实现 Ajax。
1、创建异步对象

let xmlHttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, SafarixmlHttp = new XMLHttpRequest();
} else {// code for IE6, IE5xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
}

创建的这个异步对象上有很多属性和方法,常用的有

  1. onreadystatechange:监听异步对象请求状态码readyState的改变,每当readyState改变时,就会触发onreadystatechange事件;
  2. readyState:请求状态码(readyState表示异步对象目前的状态,状态码从0到4):
    0: 表示请求未初始化,还没有调用 open();
    1: 服务器连接已建立,但是还没有调用 send();
    2: 请求已接收,正在处理中(通常现在可以从响应中获取内容头);
    3: 请求处理中,通常响应中已有部分数据可用了,没有全部完成;
    4: 当readyState状态码为4时,表示请求已完成;此阶段确认全部数据都已经解析完毕,可以通过异步对象的属性获取对应数据;
  3. status:http状态码
    http状态码表示成功的http状态码有
    xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status == 304
  4. responseText:后台返回的字符串形式的响应数据;
  5. responseXML:后台返回的XML形式的响应数据;

2、设置请求方式和请求地址
创建异步对象之后,通过open()方法设置ajax请求方式和请求地址 格式:

xmlHttp.open(“GET/POST”,“ajax-get.txt”,true)

第一个参数:请求的类型;GET 还是 POST;
第二个参数:表示请求的文件的地址url;
第三个参数:设置请求方法是不是异步async,true为异步,false为同步。AJAX存在的意义就是发异步请求,所以第三个参数永远传true;

注意:有个问题,就是IE中的缓存问题
在IE浏览器中,如果通过Ajax发送GET请求,那么IE浏览器认为,同一个URL只有一个结果,如果地址没有发生变化,它就会把上一次返回的结果,直接返回。这样我们不能实时的拿到变化后的数据。如果要想我们拿到实时数据,必须保证每次的URL都是不一样的,有两种方式:

  1. Math.random();
  2. new Date().getTime();

即在请求地址后面拼接上?t=随机数或者1970.01.01至当前的毫秒数 所以在IE中通过ajax发送get请求时,可以设置请求地址为:

xmlHttp.open("GET","ajax-get.txt?t=" + (new Date().getTime()),true);
//或
xmlHttp.open("GET","ajax-get.txt?t=" + Math.random(),true);

3、发送请求
直接通过异步对象的send()发送请求

xmlHttp.send();

特别注意的是: 如果发送POST请求,使用setRequestHeader()来添加 HTTP请求头,并在send()方法中传递要发送的数据:

xmlHttp.open("POST","ajax_test.html",true); 
xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); 
xmlHttp.send("fname=Henry&lname=Ford");

4、通过onreadystatechange监听状态变化

当异步对象的readyState发生改变,会触发onreadystatechange函数,当readyState变成为4时,表示当前状态是请求完毕的状态,同时当http的响应码status为200到300之间(包括200和300)或为304时,表示ajax请求成功;当http状态码不是200到300之间的数也不是304时,表示请求不成功

//4.监听状态变化
xmlHttp.onreadystatechange = () => {// 判断当前状态改变是请求完毕的状态吗if (xmlHttp.readyState === 4) {if (xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status == 304) {console.log("成功的接收到服务器返回的数据");}else{console.log("不成功!");}   }
}  

5、处理返回的结果

如果成功,可通过异步对象的responseText属性来获取服务器返回的字符串

接下来,我们来封装一个方法ajax()用于发送请求

ajax()方法调用:

ajax({type: 'GET',url: 'http://localhost:3000/posts',timeout: 1000,//方法设置超时时间data:[{name:'张三'}]success: data => {console.log('success', data);},error: err => {console.log('error', err);},
});

实现法ajax():

const ajax = option => {//  0.将data对象转换成字符串//处理objconst objToString = data => {data.t = new Date().getTime();let res = [];for (let key in data) {//需要将key和value转成非中文的形式,因为url不能有中文。使用encodeURIComponent();res.push(encodeURIComponent(key) + ' = ' + encodeURIComponent(data[key]));}return res.join('&');};let str = objToString(option.data || {});//  1.创建一个异步对象xmlHttp;var xmlHttp, timer;if (window.XMLHttpRequest) {xmlHttp = new XMLHttpRequest();} else if (xmlHttp) {// code for IE6, IE5xmlHttp = new ActiveXObject('Microsoft.xmlHttp');}//  2.设置请求方式和请求地址;// 判断请求的类型是POST还是GETif (option.type.toLowerCase() === 'get') {xmlHttp.open(option.type, option.url + '?' + str, true);//  3.发送请求;xmlHttp.send();} else {xmlHttp.open(option.type, option.url, true);// 注意:在post请求中,必须在open和send之间添加HTTP请求头:setRequestHeader(header,value);xmlHttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');//  3.发送请求;xmlHttp.send(str);}//  4.监听状态的变化;xmlHttp.onreadystatechange = function () {clearInterval(timer);debugger;if (xmlHttp.readyState === 4) {if ((xmlHttp.status >= 200 && xmlHttp.status < 300) || xmlHttp.status == 304) {//  5.处理返回的结果;option.success(xmlHttp.responseText); //成功后回调;} else {option.error(xmlHttp.responseText); //失败后回调;}}};//判断外界是否传入了超时时间if (option.timeout) {timer = setInterval(function () {xmlHttp.abort(); //中断请求clearInterval(timer);}, option.timeout);}
};

ajax只是一种异步请求的方式,并不特指某一种具体的实现方式,但随着使用这种方式实现网络请求时内部又包含请求的情况,就会出现回调地狱,这也是XHR的诟病之一,因此,后来才催生了更加优雅的请求方式。

2. fetch

Fetch 是在 ES6 出现的,它使用了 ES6 提出的 Promise 对象。它是 XMLHttpRequest 的替代品。
有人把它与 Ajax 作比较,其实这是不对的,我们通常所说的Ajax 是指使用 XMLHttpRequest 实现的 Ajax,所以真正应该和 XMLHttpRequest 作比较。

Fetch 是一个 API,它是真实存在的,它是基于 Promise 的。
建议阅读:MDN

fetch()的功能与 XMLHttpRequest 基本相同,但有三个差异:

  1. fetch使用 Promise,不使用回调函数,因此大大简化了写法,写起来更简洁;
  2. fetch采用模块化设计,API 分散在多个对象上(Response 对象、Request 对象、Headers 对象),更合理一些;相比之下,XMLHttpRequest 的 API 设计并不是很好,输入、输出、状态都在同一个接口管理,容易写出非常混乱的代码;
  3. fetch通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。XMLHTTPRequest 对象不支持数据流,所有的数据必须放在缓存里,不支持分块读取,必须等待全部拿到后,再一次性吐出来;

在用法上,fetch()接受一个 URL 字符串作为参数,默认向该网址发出 GET 请求,返回一个 Promise 对象。它的基本用法如下。

fetch(url).then(...).catch(...)

下面是一个demo,从服务器获取 JSON 数据。

fetch('https://api.github.com/users/ruanyf').then(response => response.json()).then(json => console.log(json)).catch(err => console.log('Request Failed', err)); 

fetch()接收到的response是一个 Stream 对象,response.json()是一个异步操作,取出所有内容,并将其转为 JSON 对象。
Promise 可以使用 await 语法改写,使得语义更清晰。

async function getJSON() {let url = 'https://api.github.com/users/ruanyf';try {let response = await fetch(url);return await response.json();} catch (error) {console.log('Request Failed', error);}
}

上面示例中,await语句必须放在try…catch里面,这样才能捕捉异步操作中可能发生的错误。

2.1 Response

fetch()请求成功以后,得到的是一个 Response 对象

const response = await fetch(url);

Response 包含的数据通过 Stream 接口异步读取,但是它还包含一些同步属性,对应 HTTP 回应的标头信息,可以立即读取。

标头信息:

  1. Response.ok:属性返回一个布尔值,表示请求是否成功,true对应 HTTP 请求的状态码 200 到 299,false对应其他的状态码;
  2. Response.status:属性返回一个数字,表示 HTTP 回应的状态码(例如200,表示成功请求);
  3. Response.statusText:属性返回一个字符串,表示 HTTP 回应的状态信息(例如请求成功以后,服务器返回"OK");
  4. Response.url:属性返回请求的 URL。如果 URL 存在跳转,该属性返回的是最终 URL;
  5. Response.type:属性返回请求的类型。可能的值如下:
    • basic:普通请求,即同源请求;
    • cors:跨域请求;
    • error:网络错误,主要用于 Service Worker;
    • opaque:如果fetch()请求的type属性设为no-cors,就会返回这个值。表示发出的是简单的跨域请求,类似表单的那种跨域请求;
    • opaqueredirect:如果fetch()请求的redirect属性设为manual,就会返回这个值;
  6. Response.redirected:属性返回一个布尔值,表示请求是否发生过跳转。

判断请求是否成功

fetch()发出请求以后,有一个很重要的注意点:只有网络错误,或者无法连接时,fetch()才会报错,其他情况都不会报错,而是认为请求成功。
这就是说,即使服务器返回的状态码是 4xx 或 5xx,fetch()也不会报错(即 Promise 不会变为 rejected状态)。

那怎么判断请求是否成功呢?

1、Response.status属性,得到 HTTP 回应的真实状态码
response.status属性只有等于 2xx (200~299),才能认定请求成功。这里不用考虑网址跳转(状态码为 3xx),因为fetch()会将跳转的状态码自动转为 200。

  1. response.ok是否为true

Response.headers

Response 对象还有一个Response.headers属性,指向一个 Headers 对象,对应 HTTP 回应的所有标头。
Headers 对象提供了以下方法,用来操作标头。

Headers.get():根据指定的键名,返回键值。
Headers.has():返回一个布尔值,表示是否包含某个标头。
Headers.set():将指定的键名设置为新的键值,如果该键名不存在则会添加。
Headers.append():添加标头。 Headers.delete():删除标头。
Headers.keys():返回一个遍历器,可以依次遍历所有键名。
Headers.values():返回一个遍历器,可以依次遍历所有键值。
Headers.entries():返回一个遍历器,可以依次遍历所有键值对([key, value])。
Headers.forEach():依次遍历标头,每个标头都会执行一次参数函数。

如:

let response =  await  fetch(url);  
response.headers.get('Content-Type')
// application/json; charset=utf-8

读取内容的方法

Response对象根据服务器返回的不同类型的数据,提供了不同的读取方法。

  • response.text():得到文本字符串;比如 HTML 文件。
  • response.json():得到 JSON 对象;
  • response.blob():得到二进制 Blob 对象;读取图片文件。
  • response.formData():得到 FormData 表单对象;主要用在 Service Worker 里面,拦截用户提交的表单,修改某些数据以后,再提交给服务器。
  • response.arrayBuffer():得到二进制 ArrayBuffer 对象;主要用于获取流媒体文件。

这5个读取方法都是异步的,返回的都是 Promise 对象。必须等到异步操作结束,才能得到服务器返回的完整数据。
如:

const response = await fetch('/users.html');
const body = await response.text();
document.body.innerHTML = body

Response.clone
Stream 对象只能读取一次,读取完就没了。这意味着,前一节的五个读取方法,只能使用一个,否则会报错。

let text =  await response.text();
let json =  await response.json();  // 报错

Response 对象提供Response.clone()方法,创建Response对象的副本,实现多次读取。

const response1 = await fetch('flowers.jpg');
const response2 = response1.clone();const myBlob1 = await response1.blob();
const myBlob2 = await response2.blob();image1.src = URL.createObjectURL(myBlob1);
image2.src = URL.createObjectURL(myBlob2);

上面示例中,response.clone()复制了一份 Response 对象,然后将同一张图片读取了两次。
Response.body
Response.body属性是 Response 对象暴露出的底层接口,返回一个 ReadableStream 对象,供用户操作。
它可以用来分块读取内容,应用之一就是显示下载的进度。

const response = await fetch('flower.jpg');
const reader = response.body.getReader();while(true) {const {done, value} = await reader.read();if (done) {break;}console.log(`Received ${value.length} bytes`)
}

response.body.getReader()方法返回一个遍历器。这个遍历器的read()方法每次返回一个对象,表示本次读取的内容块。
这个对象的done属性是一个布尔值,用来判断有没有读完;value属性是一个 arrayBuffer 数组,表示内容块的内容,而value.length属性是当前块的大小

2.2 定制 HTTP 请求

fetch()的第一个参数是 URL,还可以接受第二个参数,作为配置对象,定制发出的 HTTP 请求

fetch(url, optionObj)

HTTP 请求的方法、标头、数据体都在这个对象里面设置。
如:


const response = await fetch(url, {method: 'POST',headers: {"Content-type": "application/x-www-form-urlencoded; charset=UTF-8",},body: 'foo=bar&lorem=ipsum',
});const json = await response.json();

2.3 option API

fetch()第二个参数的完整 API 如下:

const response = fetch(url, {method: "GET",headers: {"Content-Type": "text/plain;charset=UTF-8"},body: undefined,referrer: "about:client",//用于设定fetch()请求的referer标头referrerPolicy: "no-referrer-when-downgrade",//用于设定Referer标头的规则mode: "cors", //mode属性指定请求的模式 跨域/同源credentials: "same-origin",//是否发送 Cookiecache: "default",//指定如何处理缓存 请求远程服务器与更不更新缓存redirect: "follow",//指定 HTTP 跳转的处理方法 如果页面发生跳转,fetch()跟随/报错/指向新urlintegrity: "",//指定一个哈希值,用于检查 HTTP 回应传回的数据是否等于这个预先设定的哈希值,比如,下载文件时,检查文件的 SHA-256 哈希值是否相符,确保没有被篡改keepalive: false,//为true时 表示页面卸载时,告诉浏览器在后台保持连接,继续发送数据,使用场景用户离开网页时,脚本向服务器提交一些用户行为的统计信息signal: undefined//指定一个 AbortSignal 实例,用于取消fetch()请求
});

可以去 Fetch_API查看详细api

2.4 fetch cancel

fetch()请求发送以后,如果中途想要取消,需要使用AbortController对象。
controller.abort()方法用于发出取消信号
下面是一个1秒后自动取消请求的例子。

let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);try {let response = await fetch('/long-operation', {signal: controller.signal});
} catch(err) {if (err.name == 'AbortError') {console.log('Aborted!');} else {throw err;}
}

3.axios

axios是一个用于网络请求的第三方库,是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:

  • 从浏览器中创建 XMLHttpRequest;
  • 从 node.js 发出 http 请求;
  • 支持 Promise API;
  • 拦截请求和响应;
  • 转换请求和响应数据;
  • 取消请求;
  • 自动转换JSON数据;
  • 客户端支持防止CSRF/XSRF;

3.1 基本使用

最基本的配置项应该包括:

  1. method 请求的方法(可选值: get , post 等);
  2. url 请求的地址 (必须项);
  3. data 请求发送的数据(post等请求需要);
axios({method: 'post',url: '/user/12345',data: {firstName: 'Fred',lastName: 'Flintstone'}
});

请求响应的处理在 then 和 catch 回调中,请求正常会进入 then ,请求异常则会进 catch

// 发送 POST 请求
axios({method: 'post',url: '/user/12345',data: {firstName: 'Fred',lastName: 'Flintstone'}
}).then(res => {consloe.log(res)
}).catch(err => {console.log(err)
})// 发送 GET 请求(默认的方法)
axios('/user/12345');

也可以使用axios.get()axios.post()

// 发送GET请求
axios.get('/user?ID=12345').then(function (response) {console.log(response);
}).catch(function (error) {console.log(error);
});// 发送POST请求
axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'
}).then(function (response) {console.log(response);
}).catch(function (error) {console.log(error);
});

3.2 响应数据

其中的 data 是后端返回的数据,一般只需要关注 response 中的 data 字段就行

{// `data` 由服务器提供的响应data: {},// `status` 来自服务器响应的 HTTP 状态码status: 200,// `statusText` 来自服务器响应的 HTTP 状态信息statusText: 'OK',// `headers` 服务器响应的头headers: {},// `config` 是为请求提供的配置信息config: {},request: {}
}

3.3 创建实例(封装)

可以使用自定义配置新建一个 axios 实例 axios.create([config]):

const instance = axios.create({baseURL: 'https://some-domain.com/api/',timeout: 1000,headers: {'X-Custom-Header': 'foobar'}
});

以下是实例所拥有的方法

  • request(config);
  • get(url[, config]);
  • delete(url[, config]);
  • head(url[, config]);
  • options(url[, config]);
  • post(url[, data[, config]]);
  • put(url[, data[, config]]);
  • patch(url[, data[, config]]);

axios会把这些 方法中的config 会和创建实例时指定的 config 合并到一起使用

3.4 拦截器

  • axios.interceptors.request 请求拦截器
  • axios.interceptors.response 响应拦截器
// 添加请求拦截器
axios.interceptors.request.use(function (config) {// 在发送请求之前做些什么config.header["Token"] = "xxxx"return config;
}, function (error) {// 对请求错误做些什么return Promise.reject(error);
});// 添加响应拦截器
axios.interceptors.response.use(function (response) {// 对响应数据做点什么if (response.status === 200){return response.data} else {return Promise.reject(new Error('error'))}
}, function (error) {// 对响应错误做点什么return Promise.reject(error);
});

如果想要取消拦截器,可以通过使用一个变量来接收设置拦截器时返回的实例,然后使用 eject 来取消拦截器

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

3.5 完整的请求配置

{// `url` 是用于请求的服务器 URLurl: '/user',// `method` 是创建请求时使用的方法method: 'get', // default// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URLbaseURL: 'https://some-domain.com/api/',// `transformRequest` 允许在向服务器发送前,修改请求数据// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 StreamtransformRequest: [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 专属: Streamdata: {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 requestsresponseEncoding: 'utf8', // default// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称xsrfCookieName: 'XSRF-TOKEN', // default// `xsrfHeaderName` is the name of the http header that carries the xsrf token valuexsrfHeaderName: '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 将被 rejectevalidateStatus: 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) {})
}

总结

  1. Ajax 是Async Javascript And Xml的简称,它是原生JavaScript的一种请求方案,利用 XMLHttpRequest 进行异步请求数据,实现无感刷新数据;
  2. Fetch 是 ES6 新推出的一套异步请求方案,它天生自带 Promise,同时也是原生的,如果在较小项目中为了项目大小着想和兼容性不是那么高的前提下不妨可以用它来进行异步请求也是不错的;
  3. Axios 是基于 Ajax 和 Promise 封装的一个库,可以利用Promise来更好的管控请求回调嵌套造成的回调地狱;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/855354.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「Python-docx 专栏」docx设置页眉、页眉字体、页眉对齐方式

本文目录 前言一、docx 设置页眉1、完整代码2、实际效果图3、常见问题二、docx 设置页眉及对齐方式1、完整代码2、实际效果图3、常见问题①、对齐方式讲解②、字体号与Pt的对应关系三、docx设置页眉,两段文本,两端对齐1、完整代码2、实际效果图3、需要注意的问题①、为什么使…

生成高保真度3D数字人化身:打造你的专属虚拟形象

在数字化时代,我们的虚拟形象正变得越来越重要。现在,一项前沿技术正将这一领域推向新的高度——生成高保真度的3D数字人化身。这项技术不仅可以将你的形象以3D形式呈现,更能赋予它生命,让你的虚拟形象拥有丰富的表情和动作。 一、技术简介 这项技术就像是一个高级的3D照…

信息系统项目管理师 | 信息系统安全技术

关注WX&#xff1a;CodingTechWork 信息安全概念 安全属性 秘密性&#xff1a;信息不被未授权者知晓。完整性&#xff1a;信息是正确的、真实的、未被篡改的、完整无缺。可用性&#xff1a;信息可以随时正常使用。 安全分层 设备安全 设备的稳定性&#xff1a;在一定时间…

openh264 Pskip 模式决策过程源码分析

skip模式 视频编码中的 “skip” 模式是一种优化技术&#xff0c;用于提高编码效率&#xff0c;减少不必要的编码工作。当编码器确定某个宏块&#xff08;Macroblock, MB&#xff09;在当前帧和参考帧之间没有显著的运动或变化时&#xff0c;可以采用skip模式。以下是skip模式的…

C#部分方法有什么用处?和传统方法有什么区别?什么时候用合适?

在C#中&#xff0c;部分类&#xff08;partial class&#xff09;和部分方法&#xff08;partial method&#xff09;是两个不同的概念&#xff0c;但它们经常一起使用&#xff0c;特别是在代码生成和框架设计中。下面我将分别解释这两个概念&#xff0c;并讨论它们的用处、与传…

汽车IVI中控开发入门及进阶(二十七):车载摄像头vehicle camera

前言: 在车载IVI、智能座舱系统中,有一个重要的应用场景就是视频。视频应用又可分为三种,一种是直接解码U盘、SD卡里面的视频文件进行播放,一种是手机投屏,就是把手机投屏软件已视频方式投屏到显示屏上显示,另外一种就是对视频采集设备(主要就是摄像头Camera)的视频源…

leetcode144. 二叉树的前序遍历

一、题目描述&#xff1a; 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 二、输入输出实例&#xff1a; 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]…

ubuntu查看当前系统版本

要查看当前的Ubuntu系统版本&#xff0c;可以使用以下几种方法&#xff1a; 方法一&#xff1a;使用 lsb_release 命令 这是最常用的方法&#xff0c;适用于大多数Debian系发行版&#xff0c;包括Ubuntu。 lsb_release -a这将显示类似以下的输出&#xff1a; No LSB module…

移动app必须进行安全测试吗?包括哪些测试内容?

移动App已经成为我们日常生活中不可或缺的一部分&#xff0c;无论是社交娱乐还是工作学习&#xff0c;我们都离不开这些精心设计的应用程序。然而&#xff0c;随着移动App的广泛普及和使用&#xff0c;其安全性问题也逐渐浮出水面。为了确保用户数据的安全和减少潜在的风险&…

IOS全平台去开屏广告方案,真实有效

笔者最近被苹果平台上的APP开屏广告搞得心烦意乱&#xff0c;十分想念安卓的李跳跳&#xff0c;逐在B站搜索方法&#xff0c;看到评论说圈x可以去开屏广告。 但经一番搜索&#xff0c;发现圈x要求很高且貌似小火箭的规则生态更好。接下来是最经济的最有效的解决方案&#xff1a…

数智化浪潮下的零售品牌商品计划革新

在数字化和智能化交织的时代背景下&#xff0c;零售品牌的商品计划正在经历一场前所未有的革新。这场革新不仅改变了商品计划的方式和流程&#xff0c;更重塑了零售品牌的竞争格局和市场地位。 一、数智化&#xff1a;零售品牌的新引擎 在快速变化的市场环境中&#xff0c;零…

旧电视盒子的玩法与思路

旧的电视盒子&#xff0c;和电视主板&#xff0c;只要是安卓的&#xff0c;都不用丟。 留着有大用。 第一种玩法&#xff1a;也是我刚完盒子接触到的&#xff0c;就是刷游戏机&#xff0c;一般这种是把游戏系统刷到tf卡或者优盘上面&#xff0c;不妨碍你的盒子看电视&#xf…

序列到序列模型中的注意力机制

目录 一、说明 二、编码器解码器架构中的问题&#xff1a;需要注意 2.1 编码器方面的问题&#xff1a; 2.2 解码器方面的问题&#xff1a; 三、什么是注意力机制&#xff1f; 3.1 计算 ci 值&#xff1a; 3.2 ci 的广义表示&#xff1a; 四、Bahdanau 注意 &#xff1a; 4.1. 兼…

Centos/Ubuntu等Linux系统下增加扩展4个串口以上配置操作

linux(Ubuntu、centos等&#xff09;标准发行版系统默认是最多识别到4个COM串口设备&#xff0c;超过4个设备的串口则无法识别使用&#xff0c;想要载入使用则需要手动修改下grub配置文件&#xff0c;手动指定即可&#xff01;可以参考如下步骤&#xff0c;有出入的地方大家可以…

yt-dlp:强大的跨平台视频下载器

一、引言 在当今数字时代&#xff0c;视频已成为我们获取信息和娱乐的重要途径。然而&#xff0c;由于版权和网络限制&#xff0c;我们常常无法直接在本地保存我们喜爱的视频。幸运的是&#xff0c;有一个名为yt-dlp的命令行程序&#xff0c;它可以帮助我们从YouTube.com和其他…

Tomcat 概述与部署1

一、Tomcat服务器简介 Tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器&#xff0c;是 Apache 软件基金会的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。 Tomcat 属于轻量级应…

【问题记录】解压文件出现:Cannot create symbolic link : 客户端没有所需的特权。

用7zip解压文件时候出现了如下错误&#xff1a; Cannot create symbolic link : 客户端没有所需的特权。 : C:\Users\86150\Downloads\mmpose_v1.0\mmpose.mim\tools Cannot create symbolic link : 客户端没有所需的特权。 : C:\Users\86150\Downloads\mmpose_v1.0\mmpose.mi…

自动化测试岗位的标准化求职指南(0到1)

简介&#xff1a; 自动化测试是软件开发过程中的关键环节&#xff0c;对于企业来说&#xff0c;招聘一名合适的自动化测试工程师非常重要。本文将从零开始&#xff0c;为想要从事自动化测试工作的求职者提供一份详细且规范的求职指南&#xff0c;帮助他们在自动化测试领域找到…

爱,需要学习--如何进入到一段亲密关系

[页面 7]: 亲密关系的经营&#xff0c; 是自我发展的延伸&#xff0c; 只不过和自我发展 相比&#xff0c; 亲密关系的经营有自己的逻辑&#xff0c; 它围绕着两个核心展 开。 [页面 7]: 一个核心是“关系”。“关系”不是你的事&#xff0c;也不是我的事&#xff0c;而 是发生…

猫头虎 分享已解决Bug || `Uncaught ReferenceError: x is not defined`✨

猫头虎 分享已解决Bug || Uncaught ReferenceError: x is not defined&#x1f680;✨ 摘要 ✨&#x1f4a1; 大家好&#xff0c;我是猫头虎&#xff0c;一名全栈软件工程师&#xff0c;同时也是一位科技自媒体博主。今天我要和大家分享一些前端开发过程中常见的Bug以及详细的…