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; 

 

                } 

 

        } 

 

 

 

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