AS3获取http头部的方法

Posted on September 28, 2010 by Fdream

AS3的URLLoader本身没有提供解析HTTP头部的功能,而在应用中,我们偶尔也会需要去解析HTTP头部,可以通过HTTP头部获取一些状态信息或者一些其他数据。

幸好AS3提供了Socket类,我们可以利用Socket来模拟HTTP请求,解析HTTP头部以及返回的内容。基本原理很简单:连接服务器的80端口或者其他web端口,向服务器发送请求头,基本上和下面类似:

1.            GET /web/crystal/v1.1Beta01Build011/crystal_ext-min.js HTTP/1.1 

2.            Accept:*/* 

3.            Accept-Language: zh-cn 

4.            User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 

5.            Accept-Encoding: deflate 

6.            Host: adsfile.qq.com 

7.            Connection: Keep-Alive

这里需要注意的是,由于要获取请求返回的内容,因此Accept-Encoding不能写上gzip,否则你要从gzip中解压内容啦!

在发送请求完成以后就可以等待接受数据了,接受到的是字节流,因此需要decode。AS3的ByteArray对象可以从字节流中按照一定编码读取内容。由于内容的编码不一,但是header里面是可以用UTF8读取的,因此可以先一个一个字符地读出来,到header结束后在换其他编码,比如header里面指定的编码。header结束的标记是两个换行(\r\n\r\n),因此只要独到连续两个换行就代表头部已经结束了,剩下的就是内容了,用ByteArray的readMultiByte用指定编码读取出来就可以了。

具体实现的源代码可以看这里:http://code.google.com/p/fookie/source/browse/trunk/http_loader/

 

其实现的类为HTTPLoader,和URLLoader类似,事件是一样的,使用方法也一样,不过返回的对象是一个HTTPResponse对象,包括status、headers和body三个属性。status是请求返回的状态码,headers包含所有返回的头部,body是返回的内容,content是body的别名属性,内容和body一样。

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

 

 

 

package net.fdream.io 

        /** 

         * @Script:             HTTPLoader.as 

         * @Licence:    MIT License (http://www.opensource.org/licenses/mit-license.php) 

         * @Author:     [email protected] 

         * @Website:    http://code.google.com/p/fookie/ 

         * @Version:    0.1 

         * @Creation:   Sep 27, 2010 

         * @Modified:   Sep 27, 2010 

         * @Description: 

         *    Use socket to get HTTP headers, status and content 

         * 

         * @Usage: 

         *    see it in HTTPLoader.fla 

         *     

         * @Events: 

         *    They are the same with URLLoader, just list below: 

         *    complete: 

         *        Dispatched after all the received data is decoded  

         *        and placed in the response property of the HTTPLoader object. 

         *    httpStatus: 

         *        Dispatched if response headers have received. 

         *    ioError: 

         *        Dispatched if a call to HTTPLoader.load()  

         *        results in a fatal error that terminates the download. 

         *    open: 

         *        Dispatched when the download operation commences  

         *        following a call to the HTTPLoader.load() method. 

         *    progress: 

         *        Dispatched when data is received as the download  

         *        operation progresses. 

         *    securityError: 

         *        Dispatched if a call to HTTPLoader.load() attempts to  

         *        load data from a server outside the security sandbox. 

         *     

         */ 

 

        import flash.net.Socket; 

        import flash.net.URLRequest; 

        import flash.net.URLRequestHeader; 

        import flash.events.Event; 

        import flash.events.EventDispatcher; 

        import flash.events.IEventDispatcher; 

        import flash.events.IOErrorEvent; 

        import flash.events.SecurityErrorEvent; 

        import flash.events.ProgressEvent; 

        import flash.events.HTTPStatusEvent 

        import flash.utils.ByteArray; 

 

        public class HTTPLoader extends EventDispatcher 

        { 

                public function get userAgent():String 

                { 

                        return _userAgent; 

                } 

 

                public function set userAgent(value:String):void 

                { 

                        this._userAgent = value; 

                } 

 

                public function get referer():String 

                { 

                        return _referer; 

                } 

 

                public function set referer(value:String):void 

                { 

                        this._referer = value; 

                } 

 

                public function get response():HTTPResponse 

                { 

                        return this._response; 

                } 

 

                // host to connect 

                private var _host:String = null; 

                // port to connect 

                private var _port:int = 80; 

                // path to load 

                private var _path:String = '/'; 

                // user agent of http request 

private var _userAgent:String = 'Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10'; 

                // referer 

                private var _referer:String = null; 

 

                private var _socket:Socket = new Socket(); 

                private var _request:URLRequest = null; 

                private var _bytes:Array = new Array(); 

 

                //private var _dispatcher:EventDispatcher = new EventDispatcher(); 

 

                private var _encoding:String = 'utf-8'; 

 

                // progress information  

                private var _bytesLoaded:int = 0; 

                private var _bytesTotal:int = 0; 

                private var _headerLength:int = 0; 

 

                // response 

                private var _response = {'status': 0, 'headers': {}, 'body': ''}; 

 

                // url pattern 

                //    group[1]: host 

                //    group[2]: port 

                //    group[3]: path 

                private const URL_PATTERN:RegExp = /http:\/\/([^:\/]+)(?::(\d+))?(\/.*$)/i; 

 

                /** 

                 * constructor 

                 * 

                 * @param url:String 

                 *    the request to load 

                 * @return: 

                 *    void 

                 */ 

                public function HTTPLoader(request:URLRequest = null) 

                { 

                        this._request = request; 

                } 

 

                /** 

                 * load a request 

                 * 

                 * @param request:URLRequest 

                 *    the request to load 

                 * @return:  

                 *    void 

                 */ 

                public function load(request:URLRequest = null):void 

                { 

                        if (request != null) 

                        { 

                                this._request = request; 

                        } 

 

                        if (this._request == null) 

                        { 

                                throw new Error('the request cannot be null'); 

                        } 

 

                        // parse url 

                        var match:Object = URL_PATTERN.exec(this._request.url); 

                        if (match) 

                        { 

                                this._host = match[1]; 

                                this._port = int(match[2]) || 80; 

                                this._path = match[3] || '/'; 

                        } 

                        else 

                        { 

                                throw new Error('invalid url'); 

                        } 

 

                        this._socket.addEventListener(Event.CLOSE, closeHandler); 

                        this._socket.addEventListener(Event.CONNECT, connectHandler, false, 0, true); 

                        this._socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); 

              this._socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); 

                        this._socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); 

 

                        this._socket.connect(this._host, this._port); 

                } 

 

                private function closeHandler(evt:Event) 

                { 

                        this._response.body = parseData(); 

 

                        this._response = new HTTPResponse(this._response); 

                        dispatchEvent(new Event(flash.events.Event.COMPLETE)); 

                } 

 

                private function connectHandler(evt:Event) 

                { 

                        // headers 

var headers:String = this._request.method + ' ' + this._path + ' HTTP/1.0\r\nHost: ' + this._host + '\r\nAccept: */*\r\nUser-Agent: ' + this._userAgent + '\r\nAccept-Encoding: deflate\r\nAccept-Language: zh-cn\r\nConnection: Close\r\n'; 

                        if (this._referer) 

                        { 

                                headers += 'referer: ' + this._referer + '\r\n' 

                        } 

 

                        if (this._request.requestHeaders.length) 

                        { 

                var len:int = this._request.requestHeaders.length, header:URLRequestHeader; 

                                for (var i:int = 0; i < len; i++) 

                                { 

                                        header = this._request.requestHeaders[i]; 

                                        headers += header.name + ': ' + header.value + '\r\n'; 

                                } 

                        } 

                        headers += '\r\n'; 

 

                        // send request 

                        this._socket.writeUTFBytes(headers); 

                        this._socket.flush(); 

 

                        // dispatch open event 

                        dispatchEvent(new Event(flash.events.Event.OPEN)); 

                } 

 

                private function ioErrorHandler(evt:IOErrorEvent) 

                { 

                        dispatchEvent(evt); 

                } 

 

                private function securityErrorHandler(evt:SecurityErrorEvent) 

                { 

                        dispatchEvent(evt); 

                } 

 

                private function socketDataHandler(evt:ProgressEvent) 

                { 

                        var ba:ByteArray = new ByteArray() 

                        this._socket.readBytes(ba, 0, this._socket.bytesAvailable); 

                        this._bytes.push(ba); 

                        if (this._bytes.length == 1) 

                        { 

                                parseHeaders(ba); 

                                _bytesLoaded = -this._headerLength; 

                        } 

 

                        _bytesLoaded += ba.length; 

 

                        // dispatch progress event 

dispatchEvent(new ProgressEvent(flash.events.ProgressEvent.PROGRESS, false, false, _bytesLoaded, _bytesTotal)); 

                } 

 

                private function parseHeaders(bytes:ByteArray):void 

                { 

var s:String = bytes.readUTFBytes(1), headers:Array = new Array(), header:String = '', headerEnded:Boolean = false, line:int = 0; 

                        while (bytes.bytesAvailable) 

                        { 

                                switch (s) 

                                { 

                                        case '\r': 

                                                break; 

                                        case '\n': 

                                                line++; 

                                                if (line == 2) 

                                                { 

                                                        this._response['status'] = parseInt(headers[0].split(' ')[1]); 

 

                                                        // dispatch progress event 

dispatchEvent(new HTTPStatusEvent(flash.events.HTTPStatusEvent.HTTP_STATUS, false, false, this._response['status'])); 

 

                                                        var h:Array; 

                                                        for (var i:int = 1; i < headers.length; i++) 

                                                        { 

                                                                h = headers[i].split(': '); 

                                                                this._response['headers'][h[0]] = h[1]; 

 

                                                                switch (h[0]) 

                                                                { 

                                                                        case 'Content-Type': 

                                                                                var encoding:Array = h[1].split('='); 

                                                                                if (encoding.length > 1) 

                                                                                { 

                                                                                        this._encoding = encoding[1]; 

                                                                                } 

                                                                                break; 

                                                                        case 'Content-Length': 

                                                                                this._bytesTotal = parseInt(h[1]); 

                                                                                break; 

                                                                } 

                                                        } 

                                                        this._headerLength = bytes.length - bytes.bytesAvailable; 

                                                        headerEnded = true; 

                                                } 

                                                else 

                                                { 

                                                        headers.push(header); 

                                                        header = ''; 

                                                } 

                                                break; 

                                        default: 

                                                line = 0; 

                                                header += s; 

                                                break; 

                                } 

                                if (headerEnded) 

                                { 

                                        break; 

                                } 

                                else 

                                { 

                                        s = bytes.readUTFBytes(1); 

                                } 

                        } 

                } 

 

                private function parseData():String 

                { 

                        var data:String = '', ba:ByteArray, i = 0; 

                        while (ba = this._bytes[i++]) 

                        { 

                                data += ba.readMultiByte(ba.bytesAvailable, this._encoding) 

                        } 

                        return data; 

                } 

        } 

 

 

 

 

package net.fdream.io 

 

 

        /** 

 

         * @Script:             HTTPResponse.as 

 

         * @Licence:    MIT License (http://www.opensource.org/licenses/mit-license.php) 

 

         * @Author:     [email protected] 

 

         * @Website:    http://code.google.com/p/fookie/ 

 

         * @Version:    0.1 

 

         * @Creation:   Sep 27, 2010 

 

         * @Modified:   Sep 27, 2010 

 

         * @Description: 

 

         *    HTTPResponse Object 

 

         */ 

 

 

 

        public class HTTPResponse 

 

        { 

 

                public function get headers():Object 

 

                { 

 

                        return _headers; 

 

                } 

 

 

 

                public function get status():int 

 

                { 

 

                        return _status; 

 

                } 

 

 

 

                public function get body():String 

 

                { 

 

                        return _body; 

 

                } 

 

 

 

                public function get content():String 

 

                { 

 

                        return _body; 

 

                } 

 

 

 

                private var _headers:Object = {}; 

 

                private var _status:int = 0; 

 

                private var _body:String = ''; 

 

 

 

                public function HTTPResponse(response:Object) 

 

                { 

 

                        this._headers = response.headers; 

 

                        this._status = response.status; 

 

                        this._body = response.body; 

 

                } 

 

        } 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章