一、快速入门 标准库中的 inet.http 用于创建 HTTP 客户端,用法其实非常简单,先来个最简单的例子: //导入 inet.http import inet.http;
//创建 HTTP 客户端对象 var http = inet.http();
//发送 GET 请求 var data = http.get('http://eu./get?username=user&password=pwd');
//发送 POST 请求 var data = http.post('http://eu./post',{ username = 'user'; password = 'pwd'; }); 更多例子请参考「aardio 自带范例 / 网络应用 / inet / http」。 二、分步请求
注意要在发送请求以后,请求结束以前读取 HTTP 响应头。这就像电话接通以后、挂断以前你才能听到对方的声音 —— 不难理解吧?!
import httpUtil; var ret = httpUtil.getHeader('http://www.') 另外 inet.http 也提供了直接读取 HTTP 响应头的 http.head() 函数:
只要调用 http.head() 发送 HEAD 请求,那么 inet.http 就会把全部 HTTP 响应头缓存起来,在请求结束后仍然可以使用 http.readHeader() 。 三、HTTP 方法
import wsock.tcp.client; var tcp = wsock.tcp.client() tcp.connect('www.',80)
sendData =/*********** HEAD / HTTP/1.1 Host: www. Connection: close User-Agent: Mozilla/5.0 Accept: */*; ***********/
tcp.write( sendData,'\r\n\r\n' ); headers = tcp.readTo('\r\n\r\n');//HTTP头以两个回车换行结束 tcp.close() ;
import console; console.log( headers ) console.pause(); 四、在请求结束后读取 HTTP 响应头 那么如果说不想写扩展库,也不想发送 HEAD 请求,也不想分步请求 …… 就是想要在 http.get() 或 http.post() 结束请求以后还能继续读取 HTTP 响应头行不行?!其实也是可以的,代码如下:
只要请求结束前读取过全部 HTTP 响应头, aardio 就会缓存起来,请求结束后可以继续读取 HTTP 响应头。 五、扩展库而不是修改库 那么如果不想多写一句 http.afterSend …… 该怎么办?!要不要打开 inet.http 修改一下源代码,让所有 HTTP 请求都读取所有 HTTP 请求头并缓存起来呢?! 2、把所有需求都盲目地塞进一个库,这会让一个库渐渐变得笨拙、复杂且难以扩展。 “扩展而不是修改库” ——通常是更好的选择。如果你不想多写这句 http.afterSend … ,只要简单地写一个新库扩展一下 inet.http 就可以,代码非常简单,例如: import inet.http;
class myHttp{ ctor( ... ){ this = ..inet.http( ... ); this.afterSend = lambda() this.readHeader(); }; } web.rest.client 就是一个基于 inet.http 而封装的上层库。而基于 web.rest.client 又扩展了更多的库,如下:
基于上面这些库再次扩展出来的库就更多了…… import zlib; import inet.http;
var http = inet.http(); var str = http.get('http://eu./gzip','Accept-Encoding:gzip'); 只有提前多写一句 import zlib ,inet.http 才会支持 gzip 自动解压。其实我们写 HTTP 请求不像在浏览器里看网页,大多时候我们不需要 gzip 压缩传输。仅仅因为个例需要什么东西,就强制所有人在所有时候都带上它 —— 这不是好习惯。 六、POST 用法 现在我们回到本文开始的代码:
上面 http.post 的第 2 个参数如果是一个表对象,会自动转换为如下的调用: http.post('http://eu./post' ,'username=user&password=pwd');
如果要向服务器提交 JSON ,代码需要修改如下:
上面我们使用 web.json.stringify() 函数将表对象转换为了 JSON 字符串,http.post 如果检测到 POST 数据是 JSON ,并且 HTTP 请求头中不包含 Content-Type 的定义,就会自动添加以下请求头: Content-Type: application/json; charset=utf-8 其实 inet.http 已经默默的做了很多事,以简化我们的调用代码,但仍然要注意这种简化是有底线和边界的。 七、web.rest
web.rest.jsonClient 会将参数表自动转换为 JSON,并将服务器返回的 JSON 自动解析为表对象。
八、HTTP 请求返回值 实际上 inet.http 对象发送请求的函数基本都有 3 个返回值:响应数据,错误信息,错误代码。我们前面的示例都只使用了第 1 个返回值。接收所有返回值的示例: import console; import inet.http;
//创建 HTTP 对象 var http = inet.http();
//3 个返回值:响应数据,错误信息,错误代码 var data,err,errCode = http.post( 'http://eu./post' ,'username=user&password=pwd' );
if( data ){ console.log(data); } else { if( http.statusCode ){ //服务端返回错误信息 console.log( http.lastResponse(), 'HTTP错误代码:' + http.statusCode ) } else{ //本地内部错误 console.log( err,errCode ); } }
http.close(); console.pause(); 可以使用「 aardio 工具 / 网络 / HTTP 状态码检测」查询 HTTP 错误代码( 上面的 errCode )与 HTTP 状态码( http.statusCode )的详细信息: 九、指定 HTTP 请求头 前面我们讲了如何获取 HTTP 响应头,下面我们讲一下如何自定义 HTTP 请求头。其实 inet.http 已经默认设置好了必要的 HTTP 请求头,一般并不需要自己指定 HTTP 请求头参数。我发现很多人在写这类 HTTP 请求代码时,都喜欢复制粘贴一大堆根本就没用的 HTTP 请求头 —— 这又多写一大堆代码不嫌累。有时候明明没问题还因为这些多余的请求头搞出问题。 例如 inet.http,inet.whttp 都提供了专用的 referer 属性( 自动设置值,一般不应修改 ),发送请求的 get,post 等函数也都可以指定 referer 参数 ,很明显通过 HTTP 头去指定 referer 既不必要也会错乱。 inet.http 对象的所有 HTTP 请求头属性、参数都会经过 web.joinHeaders() 函数处理并转化。这些 HTTP 请求头都允许传入字符串、表(键值对或数组)。先看个例子:
也可以使用表(键值对)指定 HTTP 头,例如: http.addHeaders = { 'Name1':'value1', 'Name2':'value2' } 也可以在 beforeSend 事件回调内写 HTTP 请求头。
也可以通过 http.get() , http.post() 等函数的参数指定 HTTP 请求头: var data = http.post('http://www./post', ,{ 'Accept-Language':'zh-CN,zh'; }); 十、多线程与界面
十一、断点续传 import console; import console.progress; import inet.httpFile;
var remoteFile = inet.httpFile( 'http://wubi./update/wubiLex.7z' ,'/.download/' )
var progress = console.progress(); remoteFile.onReceive = function(data,downSize,contentLength){ progress.addProgress((downSize/contentLength)*100 ,'正在下载 文件大小:' + math.size64(contentLength).format() ) }
//下载文件 if(remoteFile.download() ){ console.log('下载成功') } console.pause(); 如果还想给下载点加个窗口界面什么的,我们不必改动 inet.httpFile ,使用基于 inet.httpFile 的 inet.downBox 就可以方便地创建下载对话框:
十二、下载并解压远程压缩包 如果我们不但要下载对话框,还想下载压缩包,顺带解压缩 …… 或者顺带安装程序 —— 同样不必修改 inet.downBox ,有很多基于 inet.downBox 的库可以实现这些功能: zlib.httpFile //下载 + zip 解压缩 sevenZip.lzma.httpFile //下载 + lzma 解压缩 sevenZip.decoder2.httpFile //下载 + 7z 解压缩 inet.installer //下载 + 自动安装程序 标准库还有一个 inet.whttp,用法与接口与 inet.http 基本相同,一般可相互替代。inet.http 基于 WinINet,而 inet.whttp 基于 WinHTTP。一般普通桌面客户端软件(非NT服务)应当使用 inet.http。 十三、HTML 解析 对于服务器返回的 HTML ,我们可以使用 web.mshtml 或者 string.html 解析,调用 string.html 示例:
string.html 的更多用法请参考「范例 / Web 应用 / HTML 」 import console; import web.rest.htmlClient; var http = web.rest.htmlClient();
var google = http.api('https://translate.*****.cn/m?hl=zh-CN');
var htmlDoc = google.get(q='hello',sl='en',tl='zh-CN'); if(htmlDoc){ var resultContainer = htmlDoc.queryEle({'class':'result-container'}) if(resultContainer){ console.log(resultContainer.innerText()); } }
console.pause(true); |
|