您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關node中怎么利用Request實現一個HTTP請求客戶端,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
1. 安裝及簡單使用
安裝request模塊:
npm install request
Request設計為用最簡單的方法發送HTTP請求,它還支持HTTPS請求和自動重定向跟蹤:
var request = require('request'); request('http://www.baidu.com', function (error, response, body) { if (!error && response.statusCode == 200) { console.log(body) // IT筆錄主頁的HTML } })
引用request模塊后,就可以能通過request()方法來發送HTTP請求,在不指定請求選項option時,默認為GET。在上面請求中,對URLhttp://www.baidu.com
會301重定向到http://www.baidu.com。而Request會自動跟蹤URL重定向請求,默認支持10次重定向跟蹤。
2. 流(stream)操作
Node.js原生HTTP模塊實現了對HTTP請求和響應對象的流操作,Request同樣支持基于流的操作。
如,可以將任何響應流通過pipe轉接到一個文件流:
復制代碼 代碼如下:
request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))
同樣,可以將一個讀取的文件流轉接到PUT或POST請求中。這個方法會自動檢查文件擴展名,并設置一個與文件擴展名對應的content-type(當該請求頭未設置時):
復制代碼 代碼如下:
fs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))
Request也支持pipe到它自己。這樣操作時,content-type和content-length將被傳遞到其后的PUT請求中:
復制代碼 代碼如下:
request.get('http://google.com/img.png').pipe(request.put('http://mysite.com/img.png'))
與原生HTTP客戶端一樣,Request在收到請求響應時會發送一個'response'。事件回調函數中會包含一個response參數,它是一個http.IncomingMessage實例:
request .get('http://google.com/img.png') .on('response', function(response) { console.log(response.statusCode) // 200 console.log(response.headers['content-type']) // 'image/png' }) .pipe(request.put('http://mysite.com/img.png'))
當請求發生錯誤時,可以簡單的通過監聽error事件來處理:
request .get('http://mysite.com/doodle.png') .on('error', function(err) { console.log(err) }) .pipe(fs.createWriteStream('doodle.png'))
發揮一個想象:
http.createServer(function (req, resp) { if (req.url === '/doodle.png') { if (req.method === 'PUT') { req.pipe(request.put('http://mysite.com/doodle.png')) } else if (req.method === 'GET' || req.method === 'HEAD') { request.get('http://mysite.com/doodle.png').pipe(resp) } } })
也可以使用pipe()方法將一個http.ServerRequest實例轉換到一個http.ServerResponse。HTTP請求方法、請求頭、請求體數據會被發送:
http.createServer(function (req, resp) { if (req.url === '/doodle.png') { var x = request('http://mysite.com/doodle.png') req.pipe(x) x.pipe(resp) } })
通過pipe()返回的目標流,在Nodev0.5.x+版本中,可以寫到一行:
復制代碼 代碼如下:
req.pipe(request('http://mysite.com/doodle.png')).pipe(resp)
而所有這些,沒有一個新功能會與原功能有沖突,只是對其進行了擴展。還可以使用HTTP代理,請求會被自動重定向并跟蹤:
var r = request.defaults({'proxy':'http://localproxy.com'}) http.createServer(function (req, resp) { if (req.url === '/doodle.png') { r.get('http://google.com/doodle.png').pipe(resp) } })
3. Form表單
request支付application/x-www-form-urlencoded 和 multipart/form-data 編碼的form 上傳。multipart/related會引用multipartAPI。
application/x-www-form-urlencoded (URL編碼的Form)
URL編碼的Form很簡單:
request.post('http://service.com/upload', {form:{key:'value'}}) // or request.post('http://service.com/upload').form({key:'value'}) // or request.post({url:'http://service.com/upload', form: {key:'value'}}, function(err,httpResponse,body){ /* ... */ })
multipart/form-data (Multipart Form 上傳)
對于multipart/form-dataFrom文件上傳,Request使用了form-data處理。大多數情況,可以通過formData選項添加上傳文件:
var formData = { // 鍵-值對簡單值 my_field: 'my_value', // 使用 Buffers 添加數據 my_buffer: new Buffer([1, 2, 3]), // 使用 Streams 添加數據 my_file: fs.createReadStream(__dirname + '/unicycle.jpg'), // 通過數組添加 multiple 值 attachments: [ fs.createReadStream(__dirname + '/attachment1.jpg'), fs.createReadStream(__dirname + '/attachment2.jpg') ], // 添加可選的 meta-data 使用: {value: DATA, options: OPTIONS} // 對于一些流類型,需要提供手工添加 "file"-關聯 // 詳細查看 `form-data` : https://github.com/form-data/form-data custom_file: { value: fs.createReadStream('/dev/urandom'), options: { filename: 'topsecret.jpg', contentType: 'image/jpg' } } }; request.post({url:'http://service.com/upload', formData: formData}, function optionalCallback(err, httpResponse, body) { if (err) { return console.error('upload failed:', err); } console.log('Upload successful! Server responded with:', body); });
在一些更加高級的使用中,可以通過其自身的如r.form()來訪問Form數據:
// NOTE: Advanced use-case, for normal use see 'formData' usage above var r = request.post('https://cache.yisu.com/upload/information/20200622/114/74489.jpg'), {filename: 'unicycle.jpg'});
multipart/related
在一些不同的HTTP實現中,需要在multipart/related的之前、之后或前后同時添加一個newline/CRLF(通過multipart選項)。特別是在.NET WebAPI 4.0中,需要將preambleCRLF設置為true:
request({ method: 'PUT', preambleCRLF: true, postambleCRLF: true, uri: 'http://service.com/upload', multipart: [ { 'content-type': 'application/json', body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}}) }, { body: 'I am an attachment' }, { body: fs.createReadStream('image.png') } ], // alternatively pass an object containing additional options multipart: { chunked: false, data: [ { 'content-type': 'application/json', body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}}) }, { body: 'I am an attachment' } ] } }, function (error, response, body) { if (error) { return console.error('upload failed:', error); } console.log('Upload successful! Server responded with:', body); })
4. HTTP認證
在一些HTTP請求中,需要對請求對象進行身份驗證。Request提供了多種身份驗證方式:
request.get('http://some.server.com/').auth('username', 'password', false); // or request.get('http://some.server.com/', { 'auth': { 'user': 'username', 'pass': 'password', 'sendImmediately': false } }); // or request.get('http://some.server.com/').auth(null, null, true, 'bearerToken'); // or request.get('http://some.server.com/', { 'auth': { 'bearer': 'bearerToken' } });
當使用auth選項進,其可包含以下值:
user || username
pass || password
sendImmediately (可選)
bearer (可選)
而對于最終調用的auth(username, password, sendImmediately, bearer)方法來說,sendImmediately默認為true,這會導致一個 basic 或 bearer 認證頭會被發送。如果sendImmediately設置為false,request會在收到401狀態后嘗試使用一個合適的認證頭。
注意,也可以基于RFC 1738標準,在URL中添加認證信息。簡單的是使用方式是在主機的@符號前添加user:password:
var username = 'username', password = 'password', url = 'http://' + username + ':' + password + '@some.server.com'; request({url: url}, function (error, response, body) { // Do more stuff with 'body' here });
5. 自定義HTTP頭
如果需要設置自定義的HTTP請求頭,如:User-Agent,可以通過options對象設置。
var request = require('request'); var options = { url: 'https://api.github.com/repos/request/request', headers: { 'User-Agent': 'request' } }; function callback(error, response, body) { if (!error && response.statusCode == 200) { var info = JSON.parse(body); console.log(info.stargazers_count + " Stars"); console.log(info.forks_count + " Forks"); } } request(options, callback);
6. OAuth簽名
Request支持OAuth 1.0。其默認使用的簽名算法為 HMAC-SHA1:
// OAuth2.0 - 3-legged server side flow (Twitter example) // step 1 var qs = require('querystring') , oauth = { callback: 'http://mysite.com/callback/' , consumer_key: CONSUMER_KEY , consumer_secret: CONSUMER_SECRET } , url = 'https://api.twitter.com/oauth/request_token' ; request.post({url:url, oauth:oauth}, function (e, r, body) { // Ideally, you would take the body in the response // and construct a URL that a user clicks on (like a sign in button). // The verifier is only available in the response after a user has // verified with twitter that they are authorizing your app. // step 2 var req_data = qs.parse(body) var uri = 'https://api.twitter.com/oauth/authenticate' + '?' + qs.stringify({oauth_token: req_data.oauth_token}) // redirect the user to the authorize uri // step 3 // after the user is redirected back to your server var auth_data = qs.parse(body) , oauth = { consumer_key: CONSUMER_KEY , consumer_secret: CONSUMER_SECRET , token: auth_data.oauth_token , token_secret: req_data.oauth_token_secret , verifier: auth_data.oauth_verifier } , url = 'https://api.twitter.com/oauth/access_token' ; request.post({url:url, oauth:oauth}, function (e, r, body) { // ready to make signed requests on behalf of the user var perm_data = qs.parse(body) , oauth = { consumer_key: CONSUMER_KEY , consumer_secret: CONSUMER_SECRET , token: perm_data.oauth_token , token_secret: perm_data.oauth_token_secret } , url = 'https://api.twitter.com/1.1/users/show.json' , qs = { screen_name: perm_data.screen_name , user_id: perm_data.user_id } ; request.get({url:url, oauth:oauth, qs:qs, json:true}, function (e, r, user) { console.log(user) }) }) })
使用RSA-SHA1 簽名時,可傳入如下一個OAuth對象:
指定signature_method : 'RSA-SHA1'
代替consumer_secret,指定private_key字符串為 PEM format
而使用PLAINTEXT 簽名,可傳入如下一個OAuth對象:
指定signature_method : 'PLAINTEXT'
7. 代理
如果指定proxy(代理)選項后,所有的請求(及其后的重定向)都會連接到該代理服務器。
如果終端是一個httpsURL,代理會使用CONNECT請求連接到代理服務器。
首先會生成類似如下一個請求:
HTTP/1.1 CONNECT endpoint-server.com:80 Host: proxy-server.com User-Agent: whatever user agent you specify
然后建立一個到endpoint-server(終端服務器)的80端口的TCP連接,并按如下返回響應:
HTTP/1.1 200 OK
默認情況下,當代理使用http進行通訊時,request會簡單的生成一個標準的http代理請求。如,會像如下這樣生成一個請求:
HTTP/1.1 GET http://endpoint-server.com/some-url Host: proxy-server.com Other-Headers: all go here request body or whatever
通過proxyHeaderExclusiveList選項可以明確指定一些代理頭,默認會按如下方式設置:
accept accept-charset accept-encoding accept-language accept-ranges cache-control content-encoding content-language content-length content-location content-md5 content-range content-type connection date expect max-forwards pragma proxy-authorization referer te transfer-encoding user-agent via
8. UNIX域套接字
request支持到UNIX域套接字的請求:
/* Pattern */ 'http://unix:SOCKET:PATH' /* Example */ request.get('http://unix:/absolute/path/to/unix.socket:/request/path')
注意:SOCKET應該是一個到文件系統根目錄的絕對路徑。
9. TLS/SSL協議
對于使用了TLS/SSL等安全協議的請求,可以使用相關選項如cert、key、passphrase也可以使用agentOptions選項甚至使用https.globalAgent.options來設置:
var fs = require('fs') , path = require('path') , certFile = path.resolve(__dirname, 'ssl/client.crt') , keyFile = path.resolve(__dirname, 'ssl/client.key') , caFile = path.resolve(__dirname, 'ssl/ca.cert.pem') , request = require('request'); var options = { url: 'https://api.some-server.com/', cert: fs.readFileSync(certFile), key: fs.readFileSync(keyFile), passphrase: 'password', ca: fs.readFileSync(caFile) } }; request.get(options);
使用options.agentOptions
在下面示例中,我們調用一個需要API,它需要客戶端SSL證書(PEM格式)用密碼保護私鑰(PEM格式)并禁用SSLv3協議:
var fs = require('fs') , path = require('path') , certFile = path.resolve(__dirname, 'ssl/client.crt') , keyFile = path.resolve(__dirname, 'ssl/client.key') , request = require('request'); var options = { url: 'https://api.some-server.com/', agentOptions: { cert: fs.readFileSync(certFile), key: fs.readFileSync(keyFile), // 或使用 `pfx` 屬性替換 `cert` 和 `key`使用私鑰時,證書和CA證書在 PFX 或 PKCS12 格式的文件中: // pfx: fs.readFileSync(pfxFilePath), passphrase: 'password', securityOptions: 'SSL_OP_NO_SSLv3' } }; request.get(options);
如果強制使用SSLv3,則通過secureProtocol指定:
request.get({ url: 'https://api.some-server.com/', agentOptions: { secureProtocol: 'SSLv3_method' } });
10. 對HAR 1.2的支持
options.har屬性會重寫url。method, qs, headers, form, formData, body, json的值,當request.postData.params[].fileName的值不存在時,會從硬盤文件構建 multipart 數據
當HAC 請求匹配到指定規則時會執行驗證檢查,如果未匹配到則會跳過:
var request = require('request') request({ // 將會忽略 method: 'GET', uri: 'http://www.google.com', // HTTP 存檔請求對象 har: { url: 'http://www.mockbin.com/har', method: 'POST', headers: [ { name: 'content-type', value: 'application/x-www-form-urlencoded' } ], postData: { mimeType: 'application/x-www-form-urlencoded', params: [ { name: 'foo', value: 'bar' }, { name: 'hello', value: 'world' } ] } } }) // 一個 POST 請求會發送到 http://www.mockbin.com // 其請求體編碼為 application/x-www-form-urlencoded,發送內容: // foo=bar&hello=world
11. option所有可用參數
request()的請求格式有如下兩種形式:
request(options, callback); // 或 request(url, options, callback);
當使用request.put()、request.post()等便捷方法進行請求時,同樣有如下兩種形式:
request.METHOD(options, callback); // 或 request.METHOD(url, options, callback);
options表示請求選項,其中只有>url/uri是必須參數,其它都是可選值。下面是一些常用選項:
uri || url - 完整的uri字符串或可通過url.parse()解析的url對象
baseUrl - 用于基本uri的遠整字符串。大多使用request.defaults,如:對于大多數請求你相使用相同的域名。如果baseUrl 是 https://example.com/api/,那么請求/end/point?test=true 會匹配到https://example.com/api/end/point?test=true;當baseUrl指定后,uri選項必須是字符串。
method - HTTP請求方法(默認: "GET")
headers - HTTP請求頭 (默認: {})
查詢字符串相關選項:
qs - 包含查詢字符串值的對象,會被添加到uri中
qsParseOptions - 用于qs.parse方法的選項對象,或者傳入querystring.parse方法用于{sep:';', eq:':', options:{}}格式的對象
qsStringifyOptions - 用于qs.stringify 方法的選項對象,或者傳入用于querystring.stringify 方法使用{sep:';', eq:':', options:{}}格式的選項。
useQuerystring - 如果true,使用querystring 來解析查詢字符串,其它使用qs (默認: false)。設置為true時,你需要將數組序列化為foo=bar&foo=baz 而默認為 foo[0]=bar&foo[1]=baz
請求體相關選項:
body - 可用于:PATCH, POST 和 PUT 請求的請求體(發送的數據)。必須是Buffer, String 或 ReadStream。如果json 是 true,則body 必須是一個JSON化的對象。
form - 當通過對象或查詢字符串發送數據時,這一選項會設置body 為包含發送值的查詢字符串,并添加自動Content-type: application/x-www-form-urlencoded請求頭。
formData - 當發送multipart/form-data請求時使用。參見前面的Forms 一節。
multipart - 包含請求頭與body屬性的對象。會發送一個multipart/related請求。請求時使用。參見Forms。 也可以傳入一個{chunked: false, data: []},其 chunked 用于指定發送請求的 chunked 轉換編碼。如果非chunked請求,,不允許使用使用具有請求體流的數據項。
preambleCRLF - 在multipart/form-data請求之前添加一個 newline/CRLF 邊界描述
postambleCRLF - 在multipart/form-data請求之后添加一個 newline/CRLF 邊界描述
json - 設置 body(請求體) 為JSON格式,并添加Content-type: application/json請求頭。另外,也會將響應體轉換為JSON格式
jsonReviver - 一個reviver函數,會傳遞給JSON.parse() 方法用于解板響應體。
jsonReplacer - 一個 replacer 函數,會傳遞給JSON.stringify()方法用于序列化JSON請求體
認證相關選項:
auth - 包含 user || username, pass || password, 和 sendImmediately (可選)的哈希對象。
oauth - 用于 OAuth HMAC-SHA1 簽名的選項
hawk - 用于Hawk 簽名的選項。credentials 鍵必須包含必要的簽名信息,參見hawk文檔
aws - object 包含 AWS 簽名信息。需要有key、secret屬性,同樣要有bucket選項,除非已在路徑中指定bucket或請求不使用 bucket (如 GET 服務)。如果要使用 AWS v4版本,則指定sign_version 選項值為 4,默認值為2。注意: 首先要 npm install aws4
httpSignature - 用于HTTP Signature Scheme的先項,使用Joyent's簽名庫。keyId 和 key 屬性必須同時指定
重定向相關選項:
followRedirect - 跟蹤 HTTP 3xx 響應并重定向(默認: true)。這個屬性也可以指定為一個獲取單個response的函數,如果重定向繼續需要返回true 其它情況返回 false
followAllRedirects - 跟蹤非GET請求的 HTTP 3xx 響應(默認: false)
maxRedirects - 最大重定向跟蹤數量(默認: 10)
removeRefererHeader - 當發生重定向進移聊referer頭(默認: false)。注意: 如果設為 true,referer頭會設置為重定向鏈的初始請求。
編碼/壓縮相關選項:
encoding - 用于響應數據 setEncoding 頭的編碼。如果null,則 body 會返回一個 Buffer。任何情況下(除非設置為undefined) 都會將encoding 參數傳遞給 toString() 方法(默認為:utf8)。
gzip - 如果為 true,會添加一個Accept-Encoding 頭用于發送到服務器的請求內容的壓縮和解壓從服務器返回的數據
jar - 如果 true,則記錄使用的 cookies(或自定義 cookie jar)
代理相關選項:
agent - 用于http(s).Agent 的代理實例
agentClass - 或指定代理類
agentOptions - 并傳入代理選項。注: 參見 HTTPS TLS/SSL API文檔 和 代理一節
forever - 如果設置為 true 會使用 forever-agent
pool - 描述用于請求的代理的對象。如果此選項被省略,請求將使用全局代理(當允許時)。否則,請求將搜索您的自定義代理的池。如果沒有找到自定義代理,將創建一個新的代理,并將其添加到池中。注意: pool 僅在指定agent選項后可用
maxSockets屬性同樣可用于pool對象,用于設置代理最大可創建的 sockets 連接數(如:pool: {maxSockets: Infinity})
當發送 multiple 請求時,會創建一個新的pool 對象,maxSockets 將不會按預期工作。
timeout - 超時時間(毫秒)
本地代理選項:
localAddress - 用于連接網絡連接的本地接口
proxy - 使用的HTTP代理。支持代理使用基本認證,即認證信息通過url參數發送
strictSSL - 如果設置為true,則需要有效的 SSL證書。注意: 要使用自己的證書管理,則需要指定一個所創建的代理的選項。
tunnel - 控制 HTTP CONNECT 連接的隧道,可為以下值:
undefined (默認) - true 表示目標為 https, false 為其它方式
true - 總是通過CONNECT隧道請求連接到目的 代理
false - 使用GET請求方法請求目標.
proxyHeaderWhiteList -發送到代理隧道的請求頭白名單
proxyHeaderExclusiveList - 發送到代理隧道的請求頭白名單,僅用于代理而不是目標服務器
HAR相關選項:
time - 為true時,則請求-響應環(包括所有重定向)在指定毫秒內提供,響應結果的回應時長為elapsedTime
har - HAR 1.2 請求對象 Object,將處理從HAR格式重寫匹配值
callback - 或者通過選項對象傳入請求回調函數。回調函數包含以下3個參靈敏:
error - 錯誤對象(出錯時存在,通常由http.ClientRequest對象返回)
http.IncomingMessage對象
response 響應體(String、Buffer或JSON 對象)
12. 便捷方法
Request還可以使用以HTTP方法命名的便捷方法。
request.defaults(options)
返回一個正常請求API的包裝器,其默認值為所傳遞的options選項。
示例:
// 使用 baseRequest() 進行請求是會設置一個 'x-token' 請求頭 var baseRequest = request.defaults({ headers: {'x-token': 'my-token'} }) // 使用 specialRequest() 進行請求時,會包含一個在 baseRequest 中設置的 'x-token' 請求頭 // 還會有一個 'special' 請求頭 var specialRequest = baseRequest.defaults({ headers: {special: 'special value'} })
request.put
與request()方法相同,但默認method: "PUT"
request.put(url)
request.patch
與request()方法相同,但默認method: "PATCH"
request.patch(url)
request.post
與request()方法相同,但默認method: "POST"
request.post(url)
request.head
與request()方法相同,但默認method: "HEAD"
request.head(url)
request.del / request.delete
與request()方法相同,但默認method: "DELETE"
request.del(url) request.delete(url)
request.get
與request()方法相同
request.get(url)
request.cookie
創建一個新Cookie
request.cookie('key1=value1')
request.jar
創建一個新Cookie Jar
request.jar()
注:Cookie Jar用于保存所訪問網站的Cookie信息
13. 使用示例
var request = require('request') , rand = Math.floor(Math.random()*100000000).toString() ; request( { method: 'PUT' , uri: 'http://mikeal.iriscouch.com/testjs/' + rand , multipart: [ { 'content-type': 'application/json' , body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}}) } , { body: 'I am an attachment' } ] } , function (error, response, body) { if(response.statusCode == 201){ console.log('document saved as: http://mikeal.iriscouch.com/testjs/'+ rand) } else { console.log('error: '+ response.statusCode) console.log(body) } } )
為了保持向后兼容,響應壓縮默認不會啟用。要訪問gzip壓縮的響應,需要將gzip選項設置為true。這樣數據體會通過request自動解壓縮,而響應的對象將未包含壓縮數據。
var request = require('request') request( { method: 'GET' , uri: 'http://www.google.com' , gzip: true } , function (error, response, body) { // body 是解壓縮后的 response 響應體 console.log('server encoded the data as: ' + (response.headers['content-encoding'] || 'identity')) console.log('the decoded data is: ' + body) } ).on('data', function(data) { // 收到的是解壓縮后的數據 console.log('decoded chunk: ' + data) }) .on('response', function(response) { // 未修改 http.IncomingMessage object response.on('data', function(data) { // 收到的是壓縮數據 console.log('received ' + data.length + ' bytes of compressed data') }) })
Cookie默認是未啟用的,可以通過將jar選項設置為true來啟用Cookie:
var request = request.defaults({jar: true}) request('http://www.google.com', function () { request('http://images.google.com') })
使用自定義的Cookie Jar,可以將jar選項設置為一個request.jar()實例:
var j = request.jar() var request = request.defaults({jar:j}) request('http://www.google.com', function () { request('http://images.google.com') })
或
var j = request.jar(); var cookie = request.cookie('key1=value1'); var url = 'http://www.google.com'; j.setCookie(cookie, url); request({url: url, jar: j}, function () { request('http://images.google.com') })
使用自定義的Cookie存儲,可以做為request.jar()的參數傳入:
var FileCookieStore = require('tough-cookie-filestore'); // 這時 'cookies.json' 文件必須已經存在 var j = request.jar(new FileCookieStore('cookies.json')); request = request.defaults({ jar : j }) request('http://www.google.com', function() { request('http://images.google.com') }
Cookie存儲必須是一個tough-cookie且必須支持同步操作。
在請求完成后,檢查你的Cookie Jar:
var j = request.jar() request({url: 'http://www.google.com', jar: j}, function () { var cookie_string = j.getCookieString(url); // "key1=value1; key2=value2; ..." var cookies = j.getCookies(url); // [{key: 'key1', value: 'value1', domain: "www.google.com", ...}, ...] })
上述就是小編為大家分享的node中怎么利用Request實現一個HTTP請求客戶端了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。