axios 官方指南翻译

翻译原文链接https://github.com/axios/axios
axios 个人读音 :艾克瑟斯

Promise based HTTP client for the browser and node.js
翻译:基于Promise的HTTP客户端,用于浏览器和node.js

Features 特点

  • Make XMLHttpRequests from the browser (在浏览器中创建XMLHttpRequests)
  • Make http requests from node.js (在node.js中创建http请求)
  • Supports the Promise API (支持Promise API)
  • Intercept request and response (拦截请求和响应)
  • Transform request and response data (转换请求和响应数据格式)
  • Cancel requests (取消请求)
  • Automatic transforms for JSON data (自动转换JSON数据)
  • Client side support for protecting against XSRF (客户端支持阻止XSRF[跨站请求伪造]攻击)

Browser Support 浏览器支持

ChromeFireFoxSafariOperaEdgeIE
Latest ✔Latest✔Latest✔Latest✔Latest✔11✔

Installing 安装过程

  • Using npm: 使用npm安装:
$ npm install axios
  • Using bower: 使用bower安装
$ bower install axios
  • Using yarn: 使用yarn安装
$ yarn add axios
  • Using jsDelivr CDN:使用jsDelivr 静态资源加速网络
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  • Using unpkg CDN: 使用unpkg 静态资源加速网络
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

Example 案例

In order to gain the TypeScript typings (for intellisense / autocomplete) while using CommonJS imports with require() use the following approach:

翻译:为了获得TypeScript代码提示(智能提示/自动填充),使用CommonJS导入请使用require()的以下方法:

const axios = require('axios').default;

// axios. will now provide autocomplete and parameter typings
axios.method 现在将提供自动完成和参数输入

Performing a GET request 执行 Get请求


const axios = require('axios');

// Make a request for a user with a given ID 根据id查询用户
axios.get('/user?ID=12345')
  .then(function (response) {
    // handle success 成功处理
    console.log(response);
  })
  .catch(function (error) {
    // handle error 失败处理
    console.log(error);
  })
  .then(function () {
    // always executed 总会执行
  });

// Optionally the request above could also be done as 以上请求也可以这样做
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })
  .then(function () {
    // always executed
  });  

// Want to use async/await? Add the `async` keyword to your  outer function/method.
async function getUser() {
  try {
    const response = await axios.get('/user?ID=12345');
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

async/await is part of ECMAScript 2017 and is not supported in Internet Explorer and older browsers, so use with caution.
async/await 事ES 2017的内容,不支持IE浏览器和一些老的浏览器。请谨慎使用。

Performing a POST request 执行POST请求


axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

Performing multiple concurrent requests  //执行多个并发请求

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];
  });

axios API axios 接口

Requests can be made by passing the relevant config to axios.
可以通过将相关配置传递给axios来发出请求。
axios(config)

// Send a POST request  发送POST请求
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});

// GET request for remote image in node.js 在nodejs中读取远程图片
axios({
  method: 'get',
  url: 'http://bit.ly/2mTM3nY',
  responseType: 'stream'
})
  .then(function (response) {
    response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
  });

axios(url[, config])

// Send a GET request (default method)
axios(’/user/12345’);

Request method aliases 请求方法别名

For convenience aliases have been provided for all supported request methods.

翻译:为了方便,别名已经提供了所有的请求方法。

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

When using the alias methods url, method, and data properties don’t need to be specified in config.
当使用别名方法,url,method和data属性无需在config中声明。

Concurrency (Deprecated) 并发(弃用)

Please use Promise.all to replace the below functions.
请使用Promise.all 替换下面的函数。
Helper functions for dealing with concurrent requests.
处理并发请求的助手函数。

axios.all(iterable) axios.spread(callback)

Creating an instance 创建一个实例

You can create a new instance of axios with a custom config.

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

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

Instance methods 实例方法

The available instance methods are listed below. The specified config will be merged with the instance config.

实例方法有如下列表。指定的配置将与实例的配置合并。

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

Request Config 请求配置

These are the available config options for making requests. Only the url is required. Requests will default to GET if method is not specified.

翻译:这些是用于发出请求的可用配置选项。只有url是必须的。如果没有指定方法,请求将默认为GET。

{
  // `url` is the server URL that will be used for the request (请求的url地址)
  url: '/user',

  // `method` is the request method to be used when making the request (method 是发出请求时使用的请求方法)
  method: 'get', // default 默认方式

  // `baseURL` will be prepended to `url` unless `url` is absolute.(' baseURL '将被放在' url '的前面,除非url时绝对路径)
  // It can be convenient to set `baseURL` for an instance of axios to pass relative URLs
  它可以在axios实例设置baseURL值方便指定相对路径
  // to methods of that instance.
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` allows changes to the request data before it is sent to the server(transformRequest 允许在发送到服务之前更改请求数据)
  // This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'(它只适用这些请求方法‘PUT’,'POST','PATCH','DELETE')
  // The last function in the array must return a string or an instance of Buffer, ArrayBuffer,(在数组中的最后一个函数必须返回字符串或Buffer,ArrayBuffer对象)
  // FormData or Stream
  // You may modify the headers object.
  transformRequest: [function (data, headers) {
    // Do whatever you want to transform the data

    return data;
  }],

  // `transformResponse` allows changes to the response data to be made before(transformResponse 允许在响应数据之前更改响应数据)
  // it is passed to then/catch 它被传递给then/catch
  transformResponse: [function (data) {
    // Do whatever you want to transform the data

    return data;
  }],

  // `headers` are custom headers to be sent (自定义请求头)
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` are the URL parameters to be sent with the request(param是与请求一起发送的URL 参数)
  // Must be a plain object or a URLSearchParams object(必须是一个普通对象还是一个URLSearchParams对象)
  params: {
    ID: 12345
  },

  // `paramsSerializer` is an optional function in charge of serializing `params`(' parsserializer '是一个可选函数负责序列化' 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` is the data to be sent as the request body(' data '是作为请求体发送的数据)
  // Only applicable for request methods 'PUT', 'POST', 'DELETE , and 'PATCH' (仅适用PUT,POST,DELETE,PATCH这些请求方法)
  // When no `transformRequest` is set, must be of one of the following types:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - Browser only: FormData, File, Blob
  // - Node only: Stream, Buffer
  data: {
    firstName: 'Fred'
  },
  
  // syntax alternative to send data into the body(将数据发送到主体的可选语法)
  // method post
  // only the value is sent, not the key (只发送值,不发送键)
  data: 'Country=Brasil&City=Belo Horizonte',

  // `timeout` specifies the number of milliseconds before the request times out.(timeout指定请求超时的毫秒数)
  // If the request takes longer than `timeout`, the request will be aborted.(当请求耗时超过timeout,请求被放弃)
  timeout: 1000, // default is `0` (no timeout) (默认为0,没有超时时间)

  // `withCredentials` indicates whether or not cross-site Access-Control requests (“withCredentials”表示是否跨站点访问控制请求)
  // should be made using credentials
  withCredentials: false, // default

  // `adapter` allows custom handling of requests which makes testing easier.
  // Return a promise and supply a valid response (see lib/adapters/README.md).
  adapter: function (config) {
    /* ... */
  },

  // `auth` indicates that HTTP Basic auth should be used, and supplies credentials.(“auth”表示应该使用HTTP基本认证,并提供凭据。)
  // This will set an `Authorization` header, overwriting any existing
  (这将设置一个' Authorization '头,覆盖任何现有的头)
  // `Authorization` custom headers you have set using `headers`.(你得在headers参数配置自定义Authorization请求头)
  // Please note that only HTTP Basic auth is configurable through this parameter.(请注意,只有HTTP基本认证可通过此参数配置。)
  // For Bearer tokens and such, use `Authorization` custom headers instead.
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // `responseType` indicates the type of data that the server will respond with (声明服务器返回的数据类型)
  // options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
  //   browser only: 'blob'
  responseType: 'json', // default

  // `responseEncoding` indicates encoding to use for decoding responses (Node.js only) (声明返回解码使用的编码)(仅用于Node.js)
  // Note: Ignored for `responseType` of 'stream' or client-side requests
  responseEncoding: 'utf8', // default

  // `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

  // `onUploadProgress` allows handling of progress events for uploads(' onUploadProgress '允许处理上传的进度事件)
  // browser only
  onUploadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // `onDownloadProgress` allows handling of progress events for downloads(' onDownloadProgress '允许处理下载的进度事件)
  // browser only
  onDownloadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // `maxContentLength` defines the max size of the http response content in bytes allowed in node.js (' maxContentLength '定义了node.js中允许的http响应内容的最大字节大小)
  maxContentLength: 2000,

  // `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed(' maxBodyLength '(仅节点选项)定义允许的http请求内容的最大大小(以字节为单位))
  maxBodyLength: 2000,

  // `validateStatus` defines whether to resolve or reject the promise for a given(' validateStatus '定义promise中的resolve或reject)
  // HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
  // or `undefined`), the promise will be resolved; otherwise, the promise will be
  // rejected.
  validateStatus: function (status) {
    return status >= 200 && status < 300; // default
  },

  // `maxRedirects` defines the maximum number of redirects to follow in node.js.(maxRedirects定义最大重定向次数)
  // If set to 0, no redirects will be followed.
  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` and `httpsAgent` define a custom agent to be used when performing http
  // and https requests, respectively, in node.js. This allows options to be added like
  // `keepAlive` that are not enabled by default.
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // `proxy` defines the hostname, port, and protocol of the proxy server.(' proxy '定义代理服务器的主机名、端口和协议。)
  // You can also define your proxy using the conventional `http_proxy` and
  // `https_proxy` environment variables. If you are using environment variables
  // for your proxy configuration, you can also define a `no_proxy` environment
  // variable as a comma-separated list of domains that should not be proxied.
  // Use `false` to disable proxies, ignoring environment variables.
  // `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and
  // supplies credentials.
  // This will set an `Proxy-Authorization` header, overwriting any existing
  // `Proxy-Authorization` custom headers you have set using `headers`.
  // If the proxy server uses HTTPS, then you must set the protocol to `https`. 
  proxy: {
    protocol: 'https',
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // `cancelToken` specifies a cancel token that can be used to cancel the request (' cancelToken '指定一个可用于取消请求的取消令牌)
  // (see Cancellation section below for details) (详情在下面的Cancellation章节)
  cancelToken: new CancelToken(function (cancel) {
  }),

  // `decompress` indicates whether or not the response body should be decompressed 
  // automatically. If set to `true` will also remove the 'content-encoding' header 
  // from the responses objects of all decompressed responses
  // - Node only (XHR cannot turn off decompression)
  decompress: true // default

}

Response Schema 响应模式

The response for a request contains the following information.
请求响应体包含以下信息。

{
  // `data` is the response that was provided by the server(data是服务端返回的响应体)
  data: {},

  // `status` is the HTTP status code from the server response(服务的返回的HTTP状态码)
  status: 200,

  // `statusText` is the HTTP status message from the server response(服务端响应的HTTP状态码信息)
  statusText: 'OK',

  // `headers` the HTTP headers that the server responded with(headers 是服务端响应的HTTP头)
  // All header names are lower cased and can be accessed using the bracket notation.(所有的请求头名称都是小写,可以用括号访问)
  // Example: `response.headers['content-type']`
  headers: {},

  // `config` is the config that was provided to `axios` for the request(config 是axios请求的config)
  config: {},

  // `request` is the request that generated this response (request是响应体生产的请求)
  // It is the last ClientRequest instance in node.js (in redirects)
  // and an XMLHttpRequest instance in the browser
  request: {}
}

When using then, you will receive the response as follows:
当使用then,你将收到如下的请求体:

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);
  });

When using catch, or passing a rejection callback as second parameter of then, the response will be available through the error object as explained in the Handling Errors section.

翻译:当使用catch或通过拒绝回调作为then的第二个参数时,响应将通过error对象可用,如处理错误一节中所述。

Config Defaults 默认配置

You can specify config defaults that will be applied to every request.
你可以指定默认配置应用于所有请求

Global axios defaults 全局axios默认配置

axios.defaults.baseURL = 'https://api.example.com';

// Important: If axios is used with multiple domains, the AUTH_TOKEN will be sent to all of them.
// See below for an example using Custom instance defaults instead.
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

Custom instance defaults 自定义实例配置

// Set config defaults when creating the instance
const instance = axios.create({
  baseURL: 'https://api.example.com'
});

// Alter defaults after instance has been created
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;

Config order of precedence 配置优先级

Config will be merged with an order of precedence. The order is library defaults found in lib/defaults.js, then defaults property of the instance, and finally config argument for the request. The latter will take precedence over the former. Here’s an example.
配置将按照优先级的顺序被合并。顺序是 默认的库,之后是实例的默认配置,最后是请求的配置参数。最后的将覆盖之前的。如这个案例所示。


// Create an instance using the config defaults provided by the library
// At this point the timeout config value is `0` as is the default for the library
const instance = axios.create();

// Override timeout default for the library
// Now all requests using this instance will wait 2.5 seconds before timing out
instance.defaults.timeout = 2500;

// Override timeout for this request as it's known to take a long time
instance.get('/longRequest', {
  timeout: 5000
});

Interceptors 拦截器

You can intercept requests or responses before they are handled by then or catch.
你可以拦截请求或响应在他们处理then或catch之前。

// Add a request interceptor 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // Do something before request is sent 在请求之前做些处理
    return config;
  }, function (error) {
    // Do something with request error 请求错误做些处理
    return Promise.reject(error);
  });

// Add a response interceptor 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger 状态码在2xx范围,该函数将被触发
    // Do something with response data
    return response;
  }, function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error);
  });

If you need to remove an interceptor later you can.
如果你之后要移除拦截器,你可以这样做。

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

You can add interceptors to a custom instance of axios.
你可以为指定的axios实例添加拦截器


const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

Handling Errors 处理错误

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 请求被发送且返回的状态码不是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 (error.request是浏览器的XMLHttpRequest实例或Node.js http.ClientRequest的实例)
      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);
  });

Using the validateStatus config option, you can define HTTP code(s) that should throw an error.
用配置选项的validateStatus,你可以定义HTTP状态码哪些应该抛出错误。
axios.get(’/user/12345’, {
validateStatus: function (status) {
return status < 500; // Resolve only if the status code is less than 500 (只有小于500的状态码才会被处理)
}
})

Using toJSON you get an object with more information about the HTTP error.
使用toJSON 你可以获取HTTP错误的更多信息。
axios.get(’/user/12345’)
.catch(function (error) {
console.log(error.toJSON());
});

Cancellation 取消请求

You can cancel a request using a cancel token.
你可以取消请求通过使用cancel token

The axios cancel token API is based on the withdrawn cancelable promises proposal.
axios取消令牌API基于撤消的可取消承诺提议。

You can create a cancel token using the CancelToken.source factory as shown below:
你可以创建取消令牌通过使用CancelToken.source工程模式如下所示:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function (thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');

You can also create a cancel token by passing an executor function to the CancelToken constructor:
你也可以通过CancelToken 构造器传递可执行函数创建取消令牌

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();

Note: you can cancel several requests with the same cancel token.
你可以用同一个取消令牌取消多个请求

Using application/x-www-form-urlencoded format 使用application/x-www-form-urlencoded格式

By default, axios serializes JavaScript objects to JSON. To send data in the application/x-www-form-urlencoded format instead, you can use one of the following options.

翻译:默认情况下,axios将JavaScript对象序列化为JSON。要用application/x-www-form-urlencoded格式发送数据,您可以使用以下选项之一。

Browser 浏览器

In a browser, you can use the URLSearchParams API as follows:
在浏览器,你可以使用URLSearchParams API 如下所示:

const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);

Note that URLSearchParams is not supported by all browsers (see caniuse.com), but there is a polyfill available (make sure to polyfill the global environment).
注意,URLSearchParams是不支持所有浏览器的,但是这里有个组件(polyfill)可以支持所有(请确保polyfill在全局环境中)

Alternatively, you can encode data using the qs library:
或者,你也可以使用qs库对数据进行编码

const qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 }));

Or in another way (ES6),
另一种方式(ES6)

import qs from 'qs';
const data = { 'bar': 123 };
const options = {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  data: qs.stringify(data),
  url,
};
axios(options);

Node.js

Query string

In node.js, you can use the querystring module as follows:
在Nodejs中,你可以使用querystring模块如下所示:

const querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));

or ‘URLSearchParams’ from ‘url module’ as follows:
或用url 组件的URLSearchParams,如下

const url = require('url');
const params = new url.URLSearchParams({ foo: 'bar' });
axios.post('http://something.com/', params.toString());

You can also use the qs library.
你也可以使用qs 库
NOTE

The qs library is preferable if you need to stringify nested objects, as the querystring method has known issues with that use case (https://github.com/nodejs/node-v0.x-archive/issues/1665).
如果需要对嵌套对象进行字符串化,则最好使用qs库,因为querystring方法知道该用例存在问题

Form data

In node.js, you can use the form-data library as follows:
在nodejs中,你可以使用form-data库如下所示:

const FormData = require('form-data');
 
const form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_file', fs.createReadStream('/foo/bar.jpg'));

axios.post('https://example.com', form, { headers: form.getHeaders() })

Alternatively, use an interceptor:
或者使用拦截器

axios.interceptors.request.use(config => {
  if (config.data instanceof FormData) {
    Object.assign(config.headers, config.data.getHeaders());
  }
  return config;
});

Semver 语义化版本

Until axios reaches a 1.0 release, breaking changes will be released with a new minor version. For example 0.5.1, and 0.5.4 will have the same API, but 0.6.0 will have breaking changes.
翻译:在axios发布1.0版本之前,破坏性更改将通过一个新的小版本发布。例如,0.5.1和0.5.4将具有相同的API,但0.6.0将具有破坏性的更改。

Promises

axios depends on a native ES6 Promise implementation to be supported. If your environment doesn’t support ES6 Promises, you can polyfill.
axios依赖于ES6 Promise 的实现。如果您的环境不支持ES6 Promises,您可以补丁

TypeScript

axios includes TypeScript definitions.
axios 包括TypeScript定义

import axios from 'axios';
axios.get('/user?ID=12345');

Resources 其他资料

Credits 灵感

axios is heavily inspired by the http service provided in Angular. Ultimately axios is an effort to provide a standalone $http-like service for use outside of Angular.
翻译:axios的灵感很大程度上来自Angular中提供的http service。归根结底,axios是为了在Angular之外提供一个独立的类似http的服务。

License 开源协议

MIT

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月夜归醉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值