Ajax知识体系大梳理(2)

timeout

timeout属性用于指定ajax的超时时长. 通过它可以灵活地控制ajax请求时间的上限. timeout的值满足如下规则:

  • 通常设置为0时不生效.

  • 设置为字符串时, 如果字符串中全部为数字, 它会自动将字符串转化为数字, 反之该设置不生效.

  • 设置为对象时, 如果该对象能够转化为数字, 那么将设置为转化后的数字.

xhr.timeout = 0; //不生效

xhr.timeout = ‘123’; //生效, 值为123

xhr.timeout = ‘123s’; //不生效

xhr.timeout = [‘123’]; //生效, 值为123

xhr.timeout = {a:123}; //不生效

ontimeout

ontimeout方法在ajax请求超时时触发, 通过它可以在ajax请求超时时做一些后续处理.

xhr.ontimeout = function(e) {

console.error(“请求超时!!!”)

}

response responseText

均为只读属性, response表示服务器的响应内容, 相应的, responseText表示服务器响应内容的文本形式.

responseXML

只读属性, responseXML表示xml形式的响应数据, 缺省为null, 若数据不是有效的xml, 则会报错.

responseType

responseType表示响应的类型, 缺省为空字符串, 可取 "arraybuffer" , "blob" , "document" , "json" , and "text" 共五种类型.

responseURL

responseURL返回ajax请求最终的URL, 如果请求中存在重定向, 那么responseURL表示重定向之后的URL.

withCredentials

withCredentials是一个布尔值, 默认为false, 表示跨域请求中不发送cookies等信息. 当它设置为true时, cookies , authorization headers 或者TLS客户端证书 都可以正常发送和接收. 显然它的值对同域请求没有影响.

注意: 该属性适用于 IE10+, opera12+及其他现代浏览器.

abort

abort方法用于取消ajax请求, 取消后, readyState 状态将被设置为 0 (UNSENT). 如下, 调用abort 方法后, 请求将被取消.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传Event

getResponseHeader

getResponseHeader方法用于获取ajax响应头中指定name的值. 如果response headers中存在相同的name, 那么它们的值将自动以字符串的形式连接在一起.

console.log(xhr.getResponseHeader(‘Content-Type’));//“text/html”

getAllResponseHeaders

getAllResponseHeaders方法用于获取所有安全的ajax响应头, 响应头以字符串形式返回. 每个HTTP报头名称和值用冒号分隔, 如key:value, 并以\r\n结束.

xhr.onreadystatechange = function() {

if(this.readyState == this.HEADERS_RECEIVED) {

console.log(this.getAllResponseHeaders());

}

}

//Content-Type: text/html"

以上, readyState === 2 状态时, 就意味着响应头已接受完整. 此时便可以打印出完整的 response headers.

setRequestHeader

既然可以获取响应头, 那么自然也可以设置请求头, setRequestHeader就是干这个的. 如下:

//指定请求的type为json格式

xhr.setRequestHeader(“Content-type”, “application/json”);

//除此之外, 还可以设置其他的请求头

xhr.setRequestHeader(‘x-requested-with’, ‘123456’);

onerror

onerror方法用于在ajax请求出错后执行. 通常只在网络出现问题时或者ERR_CONNECTION_RESET时触发(如果请求返回的是407状态码, chrome下也会触发onerror).

upload

upload属性默认返回一个 XMLHttpRequestUpload 对象, 用于上传资源. 该对象具有如下方法:

  • onloadstart

  • onprogress

  • onabort

  • onerror

  • onload

  • ontimeout

  • onloadend

上述方法功能同 xhr 对象中同名方法一致. 其中, onprogress 事件回调方法可用于跟踪资源上传的进度.

xhr.upload.onprogress = function(e){

var percent = 100 * e.loaded / e.total |0;

console.log('upload: ’ + precent + ‘%’);

}

overrideMimeType

overrideMimeType方法用于强制指定response 的 MIME 类型, 即强制修改response的 Content-Type . 如下, 服务器返回的response的 MIME 类型为 text/plain .

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传response headers

xhr.getResponseHeader(‘Content-Type’);//“text/plain”

xhr.responseXML;//null

通过overrideMimeType方法将response的MIME类型设置为 text/xml;charset=utf-8 , 如下所示:

xhr.overrideMimeType(“text/xml; charset = utf-8”);

xhr.send();

此时虽然 response headers 如上图, 没有变化, 但 Content-Type 已替换为新值.

xhr.getResponseHeader(‘Content-Type’);//“text/xml; charset = utf-8”

此时, xhr.responseXML 也将返回DOM对象, 如下图.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传response headers

XHR一级

XHR1 即 XMLHttpRequest Level 1. XHR1时, xhr对象具有如下缺点:

  • 仅支持文本数据传输, 无法传输二进制数据.

  • 传输数据时, 没有进度信息提示, 只能提示是否完成.

  • 受浏览器 同源策略 限制, 只能请求同域资源.

  • 没有超时机制, 不方便掌控ajax请求节奏.

XHR二级

XHR2 即 XMLHttpRequest Level 2. XHR2针对XHR1的上述缺点做了如下改进:

  • 支持二进制数据, 可以上传文件, 可以使用FormData对象管理表单.

  • 提供进度提示, 可通过 xhr.upload.onprogress 事件回调方法获取传输进度.

  • 依然受 同源策略 限制, 这个安全机制不会变. XHR2新提供 Access-Control-Allow-Origin 等headers, 设置为 * 时表示允许任何域名请求, 从而实现跨域CORS访问(有关CORS详细介绍请耐心往下读).

  • 可以设置timeout 及 ontimeout, 方便设置超时时长和超时后续处理.

这里就H5新增的FormData对象举个例.

//可直接创建FormData实例

var data = new FormData();

data.append(“name”, “louis”);

xhr.send(data);

//还可以通过传入表单DOM对象来创建FormData实例

var form = document.getElementById(‘form’);

var data = new FormData(form);

data.append(“password”, “123456”);

xhr.send(data);

目前, 主流浏览器基本上都支持XHR2, 除了IE系列需要IE10及更高版本. 因此IE10以下是不支持XHR2的.

那么问题来了, IE7, 8,9的用户怎么办? 很遗憾, 这些用户是比较尴尬的. 对于IE8,9而言, 只有一个阉割版的 XDomainRequest 可用,IE7则没有. 估计IE7用户只能哭晕在厕所了.

XDomainRequest

XDomainRequest 对象是IE8,9折腾出来的, 用于支持CORS请求非成熟的解决方案. 以至于IE10中直接移除了它, 并重新回到了 XMLHttpRequest 的怀抱.

XDomainRequest 仅可用于发送 GET和 POST 请求. 如下即创建过程.

var xdr = new XDomainRequest();

xdr具有如下属性:

  • timeout

  • responseText

如下方法:

  • open: 只能接收Method,和url两个参数. 只能发送异步请求.

  • send

  • abort

如下事件回调:

  • onprogress

  • ontimeout

  • onerror

  • onload

除了缺少一些方法外, XDomainRequest 基本上就和 XMLHttpRequest 的使用方式保持一致.

必须要明确的是:

  • XDomainRequest 不支持跨域传输cookie.

  • 只能设置请求头的Content-Type字段, 且不能访问响应头信息.

$.ajax

$.ajax是jquery对原生ajax的一次封装. 通过封装ajax, jquery抹平了不同版本浏览器异步http的差异性, 取而代之的是高度统一的api. jquery作为js类库时代的先驱, 对前端发展有着深远的影响. 了解并熟悉其ajax方法, 不可谓不重要.

参数列表

$.ajax() 只有一个参数, 该参数为key-value设置对象. 实际上, jq发送的所有ajax请求, 都是通过调用该ajax方法实现的. 它的详细参数如下表:

| 序号 | 参数 | 类型 | 描述 |

| — | — | — | — |

| 1 | accepts | PlainObject | 用于通知服务器该请求需要接收何种类型的返回结果. 如有必要, 推荐在 $.ajaxSetup()方法中设置一次. |

| 2 | async | Boolean | 默认为true, 即异步. |

| 3 | beforeSend | Function | 请求发送前的回调, 默认传入参数jqXHR和settings. 函数内显式返回false将取消本次请求. |

| 4 | cache | Boolean | 请求是否开启缓存, 默认为true, 如不需要缓存请设置为false. 不过, dataType为"script"和"jsonp"时默认为false. |

| 5 | complete | Function | 请求完成后的回调(请求success 和 error之后均调用), 默认传入参数jqXHR和textStatus(请求状态, 取值为 “success”,“notmodified”,“error”,“timeout”,“abort”,"parsererror"之一). 从jq1.5开始, complete可以设置为一个包含函数的数组. 如此每个函数将依次被调用. |

| 6 | contents | PlainObject | 一个以"{字符串/正则表达式}"配对的对象, 根据给定的内容类型, 解析请求的返回结果. |

| 7 | contentType | String | 编码类型, 相对应于http请求头域的"Content-Type"字段. 默认值为"application/x-www-form-urlencoded; charset=UTF-8". |

| 8 | context | Object | 设置ajax回调函数的上下文. 默认上下文为ajax请求传入的参数设置对象. 如设置为document.body, 那么所有ajax回调函数中将以body为上下文. |

| 9 | converters | PlainObject | 一个数据类型到数据类型转换器的对象. 默认为 {"* text": window.String, "text html": true, "text json": jQuery.parseJSON, "text xml": jQuery.parseXML} . 如设置converters:{"json jsonp": function(msg){}} |

| 10 | crossDomain | Boolean | 默认同域请求为false, 跨域请求为true. |

| 11 | data | Object, Array | 发送到服务器的数据, 默认data为键值对格式对象, 若data为数组则按照traditional参数的值, 自动转化为一个同名的多值查询字符串. 如{a:1,b:2}将转换为"&a=1&b=2". |

| 12 | dataFilter | Function | 处理XMLHttpRequest原始响应数据的回调, 默认传入data和type参数, data是Ajax返回的原始数据, type是调用$.ajax时提供的dataType参数 |

| 13 | dataType | String | 预期服务器返回的数据类型, 可设置为"xml",“html”,“script”,“json”,“jsonp”,"text"之一, 其中设置为"xml"或"text"类型时, 数据不会经过处理. |

| 14 | error | Function | 请求失败时的回调函数, 默认传入jqXHR(jq1.4以前为原生xhr对象),textStatus(请求状态,取值为null,“timeout”,“error”,“abort” 或 “parsererror”),errorString(错误内容), 当一个HTTP错误发生时, errorThrown 接收HTTP状态的文本部分,比如"Not Found"等. 从jq1.5开始, error可以设置为一个包含函数的数组. 如此每个函数将依次被调用.注意: 跨域脚本和JSONP请求时error不被调用. |

| 15 | global | Boolean | 表示是否触发全局ajax事件, 默认为true. 设为false将不再触发ajaxStart,ajaxStop,ajaxSend,ajaxError等. 跨站脚本和jsonp请求, 该值自动设置为false. |

| 16 | headers | PlainObject | 设置请求头, 格式为k-v键值对对象. 由于该设置会在beforeSend函数被调用之前生效, 因此可在beforeSend函数内覆盖该对象. |

| 17 | ifModified | Boolean | 只有上次请求响应改变时, 才允许请求成功. 它使用HTTP包的Last-Modified 头信息判断, 默认为false. 若设置为true, 且数据自从上次请求后没有更改过就会报错. |

| 18 | isLocal | Boolean | 运行当前环境设置为"本地",默认为false, 若设置为true, 将影响请求发送时的协议. |

| 19 | jsonp | String | 显式指定jsonp请求中的回调函数的名称. 如jsonp:cb, jq会将cb代替callback, 以 "cb=?"传给服务器. 从jq1.5开始, 若设置jsonp:false, 那么需要明确设置jsonpCallback:“callbackName”. |

| 20 | jsonpCallback | String,Function | 为jsonp请求指定一个回调函数名, 以取代jq自动生成的随机函数名. 从jq1.5开始, 可以将该属性设置为一个函数, 函数的返回值就是jsonpCallback的结果. |

| 21 | mimeType | String | 设置一个MIME类型, 以覆盖xhr的MIM类型(jq1.5新增) |

| 22 | password | String | 设置认证请求中的密码 |

| 23 | processData | Boolean | jq的ajax方法默认会将传入的data隐式转换为查询字符串(如"&a=1&b=2"), 以配合 默认内容类型 “application/x-www-form-urlencoded”, 如果不希望转换请设置为false. angular中想要禁用默认转换, 需要重写transformRequest方法. |

| 24 | scriptCharset | String | 仅在"script"请求中使用(如跨域jsonp, dataType为"script"类型). 显式指定时, 请求中将在script标签上设置charset属性, 可在发现本地和远程编码不一致时使用. |

| 25 | statusCode | PlainObject | 一组http状态码和回调函数对应的键值对对象. 该对象以 {404:function(){}} 这种形式表示. 可用于根据不同的http状态码, 执行不同的回调.(jq1.5新增) |

| 26 | timeout | Number | 设置超时时间. |

| 27 | traditional | Boolean | 是否按照默认方式序列化data对象, 默认值为false. |

| 28 | type | String | 可以设置为8种http method之一, jq中不区分大小写. |

| 29 | url | String | 请求的uri地址. |

| 30 | username | String | 设置认证请求中的用户名 |

| 31 | xhr | Function | 在回调内创建并返回xhr对象 |

| 32 | xhrFields | PlainObject | 键值对对象, 用于设置原生的xhr对象, 如可用来设置withCredentials:true(jq1.5.1新增) |

支持promise

$.ajax() 方法返回jqXHR对象(jq1.5起), 如果使用的不是XMLHttpRequest对象时, 如jsonp请求, 返回的jqXHR对象将尽可能模拟原生的xhr. 从jq1.5起, 返回的jqXHR对象实现了promise接口, 具有如下新方法.

| 新方法 | 被替代的老方法(jq1.8起弃用) |

| — | — |

| done(function(data, textStatus, jqXHR) {}) | success |

| fail(function(jqXHR, textStatus, errorThrown) {}) | error |

| always(function(data or jqXHR, textStatus, jqXHR or errorThrown) {}) | complete |

从jq1.6开始, done, fail, always按照FIFO队列可以分配多个回调.

使用转换器

$.ajax() 的转换器可以将支持的数据类型映射到其它数据类型. 如果需要将自定义数据类型映射到已知的类型. 需要使用 contents 选项在响应的 “Content-Type” 和实际数据类型之间添加一个转换函数.

$.ajaxSetup({

contents: {

myContentType: /myContentType/

},

converters: {

“myContentType json”: function(data) {

//TODO something

return newData;

}

}

});

转换一个支持的类型为自定义类型, 然后再返回. 如 text—>myContentType—>json.

$.ajaxSetup({

contents: {

myContentType: /myContentType/

},

converters: {

“text myContentType”: true,

“myContentType json”: function(data) {

//TODO something

return newData;

}

}

});

事件触发顺序

$.ajax()方法触发的事件纷繁复杂, 有将近20个之多. 为了囊括最多的事件, 这里以一次成功的上传请求为例, 以下是它们的调用顺序(请求出现错误时的顺序, 请自行对应).

| 序号 | 事件名称 | 是否全局事件 | 是否能关闭 | 默认形参 |

| — | — | — | — | — |

| 1 | $.ajaxPrefilter | ✔️ | ❌ | function(options, originalOptions, jqXHR){} |

| 2 | $(document).ajaxStar | ✔️ | ✔️ | function(){}(只在当前无激活ajax时触发) |

| 3 | beforeSend | ❌ | - | function(jqXHR, settings){} |

| 4 | $(document).ajaxSend | ✔️ | ✔️ | function(){} |

| 5 | xhr.onloadstart | - | - | ProgressEvent |

| 6 | xhr.upload.onloadstart | - | - | ProgressEvent |

| 7 | xhr.upload.onprogress | - | - | ProgressEvent |

| 8 | xhr.upload.onload | - | - | ProgressEvent |

| 9 | xhr.upload.onloadend | - | - | ProgressEvent |

| 10 | xhr.onprogress | - | - | ProgressEvent |

| 11 | xhr.onload | - | - | ProgressEvent |

| 12 | success(弃用) | ❌ | - | function(data, textStatus, jqXHR){} |

| 13 | $(document).ajaxSuccess | ✔️ | ✔️ | function(event, jqXHR, options){} |

| 14 | complete(弃用) | ❌ | - | function(jqXHR, textStatus){} |

| 15 | $(document).ajaxComplete | ✔️ | ✔️ | function(event, jqXHR, textStatus) |

| 16 | $(document).ajaxStop | ✔️ | ✔️ | function(){} |

| 17 | xhr.onloadend | - | - | ProgressEvent |

从jq1.8起, 对于函数 ajaxStartajaxSendajaxSuccessajaxCompleteajaxStop , 只能为document对象绑定事件处理函数, 为其他元素绑定的事件处理函数不会起作用.

Axios

实际上, 如果你仅仅只是想要一个不错的http库, 相比于庞大臃肿的jquery, 短小精悍的Axios可能更加适合你. 原因如下:

  • Axios支持node, jquery并不支持.

  • Axios基于promise语法, jq3.0才开始全面支持.

  • Axios短小精悍, 更加适合http场景, jquery大而全, 加载较慢.

  • vue作者尤大放弃推荐vue-resource, 转向推荐Axios. 以下为尤大原话.

“最近团队讨论了一下, Ajax 本身跟 Vue 并没有什么需要特别整合的地方, 使用 fetch polyfill 或是 axios、superagent 等等都可以起到同等的效果, vue-resource 提供的价值和其维护成本相比并不划算, 所以决定在不久以后取消对 vue-resource 的官方推荐.”

Axios大小仅12k, 目前最新版本号为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传npm version

语法上Axios基本就和promise一样, 在then方法中处理回调, 在catch方法中处理异常. 如下:

axios.get(“https://api.github.com/users/louiszhai”)

.then(function(response){

console.log(response);

})

.catch(function (error) {

console.log(error);

});

除了get, 它还支持post, delete, head, put, patch, request请求. 具体使用攻略, 请戳这里: axios .

如需在网页上引入 Axios, 可以链接CDN axios | Bootstrap中文网开源项目免费 CDN 服务 或者将其下载到本地.

Fetch

说到ajax, 就不得不提及fetch, 由于篇幅较长, fetch已从本文中独立出来, 请戳 Fetch进阶指南 .

ajax跨域请求

什么是CORS

CORS是一个W3C(World Wide Web)标准, 全称是跨域资源共享(Cross-origin resource sharing).它允许浏览器向跨域服务器, 发出异步http请求, 从而克服了ajax受同源策略的限制. 实际上, 浏览器不会拦截不合法的跨域请求, 而是拦截了他们的响应, 因此即使请求不合法, 很多时候, 服务器依然收到了请求.(Chrome和Firefox下https网站不允许发送http异步请求除外)

通常, 一次跨域访问拥有如下流程:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

移动端CORS兼容性

当前几乎所有的桌面浏览器(Internet Explorer 8+, Firefox 3.5+, Safari 4+和 Chrome 3+)都可通过名为跨域资源共享的协议支持ajax跨域调用.

那么移动端兼容性又如何呢? 请看下图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传cors-mobile

可见, CORS的技术在IOS Safari7.1及Android webview2.3中就早已支持, 即使低版本下webview的canvas在使用跨域的video或图片时会有问题, 也丝毫不影响CORS的在移动端的使用. 至此, 我们就可以放心大胆的去应用CORS了.

CORS有关的headers
  1. HTTP Response Header(服务器提供):
  • Access-Control-Allow-Origin: 指定允许哪些源的网页发送请求.

  • Access-Control-Allow-Credentials: 指定是否允许cookie发送.

  • Access-Control-Allow-Methods: 指定允许哪些请求方法.

  • Access-Control-Allow-Headers: 指定允许哪些常规的头域字段, 比如说 Content-Type.

  • Access-Control-Expose-Headers: 指定允许哪些额外的头域字段, 比如说 X-Custom-Header.

该字段可省略. CORS请求时, xhr.getResponseHeader() 方法默认只能获取6个基本字段: Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma . 如果需要获取其他字段, 就需要在Access-Control-Expose-Headers 中指定. 如上, 这样xhr.getResponseHeader(‘X-Custom-Header’) 才能返回X-Custom-Header字段的值.(该部分摘自阮一峰老师博客)

  • Access-Control-Max-Age: 指定preflight OPTIONS请求的有效期, 单位为秒.
  1. HTTP Request Header(浏览器OPTIONS请求默认自带):
  • Access-Control-Request-Method: 告知服务器,浏览器将发送哪种请求, 比如说POST.

  • Access-Control-Request-Headers: 告知服务器, 浏览器将包含哪些额外的头域字段.

  1. 以下所有的header name 是被拒绝的:
  • Accept-Charset

  • Accept-Encoding

  • Access-Control-Request-Headers

  • Access-Control-Request-Method

  • Connection

  • Content-Length

  • Cookie

  • Cookie2

  • Date

  • DNT

  • Expect

  • Host

  • Keep-Alive

  • Origin

  • Referer

  • TE

  • Trailer

  • Transfer-Encoding

  • Upgrade

  • Via

  • 包含以Proxy- 或 Sec- 开头的header name

CORS请求

CORS请求分为两种, ① 简单请求; ② 非简单请求.

满足如下两个条件便是简单请求, 反之则为非简单请求.(CORS请求部分摘自阮一峰老师博客)

  1. 请求是以下三种之一:
  • HEAD

  • GET

  • POST

  1. http头域不超出以下几种字段:
  • Accept

  • Accept-Language

  • Content-Language

  • Last-Event-ID

  • Content-Type字段限三个值 application/x-www-form-urlencodedmultipart/form-datatext/plain

对于简单请求, 浏览器将发送一次http请求, 同时在Request头域中增加 Origin 字段, 用来标示请求发起的源, 服务器根据这个源采取不同的响应策略. 若服务器认为该请求合法, 那么需要往返回的 HTTP Response 中添加 Access-Control-* 等字段.( Access-Control-* 相关字段解析请阅读我之前写的CORS 跨域访问 )

最后

面试一面会问很多基础问题,而这些基础问题基本上在网上搜索,面试题都会很多很多。最好把准备一下常见的面试问题,毕竟面试也相当与一次考试,所以找工作面试的准备千万别偷懒。面试就跟考试一样的,时间长了不复习,现场表现肯定不会太好。表现的不好面试官不可能说,我猜他没发挥好,我录用他吧。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

96道前端面试题:

常用算法面试题:

前端基础面试题:
内容主要包括HTML,CSS,JavaScript,浏览器,性能优化

ORS请求部分摘自阮一峰老师博客)

  1. 请求是以下三种之一:
  • HEAD

  • GET

  • POST

  1. http头域不超出以下几种字段:
  • Accept

  • Accept-Language

  • Content-Language

  • Last-Event-ID

  • Content-Type字段限三个值 application/x-www-form-urlencodedmultipart/form-datatext/plain

对于简单请求, 浏览器将发送一次http请求, 同时在Request头域中增加 Origin 字段, 用来标示请求发起的源, 服务器根据这个源采取不同的响应策略. 若服务器认为该请求合法, 那么需要往返回的 HTTP Response 中添加 Access-Control-* 等字段.( Access-Control-* 相关字段解析请阅读我之前写的CORS 跨域访问 )

最后

面试一面会问很多基础问题,而这些基础问题基本上在网上搜索,面试题都会很多很多。最好把准备一下常见的面试问题,毕竟面试也相当与一次考试,所以找工作面试的准备千万别偷懒。面试就跟考试一样的,时间长了不复习,现场表现肯定不会太好。表现的不好面试官不可能说,我猜他没发挥好,我录用他吧。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

96道前端面试题:

  • [外链图片转存中…(img-w63v6Vs2-1714248390803)]

常用算法面试题:

  • [外链图片转存中…(img-qPh491C4-1714248390803)]

前端基础面试题:
内容主要包括HTML,CSS,JavaScript,浏览器,性能优化

  • 13
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值