mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-27 19:25:11 +08:00
Send HEADERS_RECEIVED and LOADING events on Android
Summary: Send part of the response body every 100 ms if the client has set onreadystatechange. This is done by using the same events as the iOS code and removing the callback that Android previously used. Reconsolidate iOS and Android implementations. Closes #3772 public Reviewed By: mkonicek Differential Revision: D2647005 fb-gh-sync-id: d006e566867fa47d5f8dff71219cb390bcb8e15a
This commit is contained in:
committed by
facebook-github-bot-3
parent
a99fabdfea
commit
4d4c48d32b
@@ -25,7 +25,7 @@ var generateRequestId = function() {
|
||||
*/
|
||||
class RCTNetworking {
|
||||
|
||||
static sendRequest(method, url, headers, data, callback) {
|
||||
static sendRequest(method, url, headers, data, useIncrementalUpdates) {
|
||||
var requestId = generateRequestId();
|
||||
RCTNetworkingNative.sendRequest(
|
||||
method,
|
||||
@@ -33,7 +33,7 @@ class RCTNetworking {
|
||||
requestId,
|
||||
headers,
|
||||
data,
|
||||
callback);
|
||||
useIncrementalUpdates);
|
||||
return requestId;
|
||||
}
|
||||
|
||||
|
||||
13
Libraries/Network/RCTNetworking.ios.js
Normal file
13
Libraries/Network/RCTNetworking.ios.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule RCTNetworking
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = require('NativeModules').Networking;
|
||||
@@ -26,14 +26,6 @@ function convertHeadersMapToArray(headers: Object): Array<Header> {
|
||||
}
|
||||
|
||||
class XMLHttpRequest extends XMLHttpRequestBase {
|
||||
|
||||
_requestId: ?number;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._requestId = null;
|
||||
}
|
||||
|
||||
sendImpl(method: ?string, url: ?string, headers: Object, data: any): void {
|
||||
var body;
|
||||
if (typeof data === 'string') {
|
||||
@@ -49,17 +41,15 @@ class XMLHttpRequest extends XMLHttpRequestBase {
|
||||
body = data;
|
||||
}
|
||||
|
||||
this._requestId = RCTNetworking.sendRequest(
|
||||
var useIncrementalUpdates = this.onreadystatechange ? true : false;
|
||||
var requestId = RCTNetworking.sendRequest(
|
||||
method,
|
||||
url,
|
||||
convertHeadersMapToArray(headers),
|
||||
body,
|
||||
this.callback.bind(this)
|
||||
useIncrementalUpdates
|
||||
);
|
||||
}
|
||||
|
||||
abortImpl(): void {
|
||||
this._requestId && RCTNetworking.abortRequest(this._requestId);
|
||||
this.didCreateRequest(requestId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,95 +12,18 @@
|
||||
'use strict';
|
||||
|
||||
var FormData = require('FormData');
|
||||
var RCTNetworking = require('NativeModules').Networking;
|
||||
var RCTNetworking = require('RCTNetworking');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
|
||||
var XMLHttpRequestBase = require('XMLHttpRequestBase');
|
||||
|
||||
class XMLHttpRequest extends XMLHttpRequestBase {
|
||||
|
||||
_requestId: ?number;
|
||||
_subscriptions: [any];
|
||||
upload: {
|
||||
onprogress?: (event: Object) => void;
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._requestId = null;
|
||||
this._subscriptions = [];
|
||||
// iOS supports upload
|
||||
this.upload = {};
|
||||
}
|
||||
|
||||
_didCreateRequest(requestId: number): void {
|
||||
this._requestId = requestId;
|
||||
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
|
||||
'didSendNetworkData',
|
||||
(args) => this._didUploadProgress.call(this, args[0], args[1], args[2])
|
||||
));
|
||||
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
|
||||
'didReceiveNetworkResponse',
|
||||
(args) => this._didReceiveResponse.call(this, args[0], args[1], args[2])
|
||||
));
|
||||
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
|
||||
'didReceiveNetworkData',
|
||||
(args) => this._didReceiveData.call(this, args[0], args[1])
|
||||
));
|
||||
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
|
||||
'didCompleteNetworkResponse',
|
||||
(args) => this._didCompleteResponse.call(this, args[0], args[1])
|
||||
));
|
||||
}
|
||||
|
||||
_didUploadProgress(requestId: number, progress: number, total: number): void {
|
||||
if (requestId === this._requestId && this.upload.onprogress) {
|
||||
var event = {
|
||||
lengthComputable: true,
|
||||
loaded: progress,
|
||||
total,
|
||||
};
|
||||
this.upload.onprogress(event);
|
||||
}
|
||||
}
|
||||
|
||||
_didReceiveResponse(requestId: number, status: number, responseHeaders: ?Object): void {
|
||||
if (requestId === this._requestId) {
|
||||
this.status = status;
|
||||
this.setResponseHeaders(responseHeaders);
|
||||
this.setReadyState(this.HEADERS_RECEIVED);
|
||||
}
|
||||
}
|
||||
|
||||
_didReceiveData(requestId: number, responseText: string): void {
|
||||
if (requestId === this._requestId) {
|
||||
if (!this.responseText) {
|
||||
this.responseText = responseText;
|
||||
} else {
|
||||
this.responseText += responseText;
|
||||
}
|
||||
this.setReadyState(this.LOADING);
|
||||
}
|
||||
}
|
||||
|
||||
_didCompleteResponse(requestId: number, error: string): void {
|
||||
if (requestId === this._requestId) {
|
||||
if (error) {
|
||||
this.responseText = error;
|
||||
}
|
||||
this._clearSubscriptions();
|
||||
this._requestId = null;
|
||||
this.setReadyState(this.DONE);
|
||||
}
|
||||
}
|
||||
|
||||
_clearSubscriptions(): void {
|
||||
for (var i = 0; i < this._subscriptions.length; i++) {
|
||||
var sub = this._subscriptions[i];
|
||||
sub.remove();
|
||||
}
|
||||
this._subscriptions = [];
|
||||
}
|
||||
|
||||
sendImpl(method: ?string, url: ?string, headers: Object, data: any): void {
|
||||
if (typeof data === 'string') {
|
||||
data = {string: data};
|
||||
@@ -115,17 +38,9 @@ class XMLHttpRequest extends XMLHttpRequestBase {
|
||||
headers,
|
||||
incrementalUpdates: this.onreadystatechange ? true : false,
|
||||
},
|
||||
this._didCreateRequest.bind(this)
|
||||
this.didCreateRequest.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
abortImpl(): void {
|
||||
if (this._requestId) {
|
||||
RCTNetworking.cancelRequest(this._requestId);
|
||||
this._clearSubscriptions();
|
||||
this._requestId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = XMLHttpRequest;
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var RCTNetworking = require('RCTNetworking');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
|
||||
/**
|
||||
* Shared base for platform-specific XMLHttpRequest implementations.
|
||||
*/
|
||||
@@ -30,6 +33,13 @@ class XMLHttpRequestBase {
|
||||
responseText: ?string;
|
||||
status: number;
|
||||
|
||||
upload: ?{
|
||||
onprogress?: (event: Object) => void;
|
||||
};
|
||||
|
||||
_requestId: ?number;
|
||||
_subscriptions: [any];
|
||||
|
||||
_method: ?string;
|
||||
_url: ?string;
|
||||
_headers: Object;
|
||||
@@ -60,9 +70,81 @@ class XMLHttpRequestBase {
|
||||
this.responseText = '';
|
||||
this.status = 0;
|
||||
|
||||
this._requestId = null;
|
||||
|
||||
this._headers = {};
|
||||
this._sent = false;
|
||||
this._lowerCaseResponseHeaders = {};
|
||||
|
||||
this._clearSubscriptions();
|
||||
}
|
||||
|
||||
didCreateRequest(requestId: number): void {
|
||||
this._requestId = requestId;
|
||||
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
|
||||
'didSendNetworkData',
|
||||
(args) => this._didUploadProgress.call(this, ...args)
|
||||
));
|
||||
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
|
||||
'didReceiveNetworkResponse',
|
||||
(args) => this._didReceiveResponse.call(this, ...args)
|
||||
));
|
||||
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
|
||||
'didReceiveNetworkData',
|
||||
(args) => this._didReceiveData.call(this, ...args)
|
||||
));
|
||||
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
|
||||
'didCompleteNetworkResponse',
|
||||
(args) => this._didCompleteResponse.call(this, ...args)
|
||||
));
|
||||
}
|
||||
|
||||
_didUploadProgress(requestId: number, progress: number, total: number): void {
|
||||
if (requestId === this._requestId && this.upload && this.upload.onprogress) {
|
||||
var event = {
|
||||
lengthComputable: true,
|
||||
loaded: progress,
|
||||
total,
|
||||
};
|
||||
this.upload.onprogress(event);
|
||||
}
|
||||
}
|
||||
|
||||
_didReceiveResponse(requestId: number, status: number, responseHeaders: ?Object): void {
|
||||
if (requestId === this._requestId) {
|
||||
this.status = status;
|
||||
this.setResponseHeaders(responseHeaders);
|
||||
this.setReadyState(this.HEADERS_RECEIVED);
|
||||
}
|
||||
}
|
||||
|
||||
_didReceiveData(requestId: number, responseText: string): void {
|
||||
if (requestId === this._requestId) {
|
||||
if (!this.responseText) {
|
||||
this.responseText = responseText;
|
||||
} else {
|
||||
this.responseText += responseText;
|
||||
}
|
||||
this.setReadyState(this.LOADING);
|
||||
}
|
||||
}
|
||||
|
||||
_didCompleteResponse(requestId: number, error: string): void {
|
||||
if (requestId === this._requestId) {
|
||||
if (error) {
|
||||
this.responseText = error;
|
||||
}
|
||||
this._clearSubscriptions();
|
||||
this._requestId = null;
|
||||
this.setReadyState(this.DONE);
|
||||
}
|
||||
}
|
||||
|
||||
_clearSubscriptions(): void {
|
||||
(this._subscriptions || []).forEach(sub => {
|
||||
sub.remove();
|
||||
});
|
||||
this._subscriptions = [];
|
||||
}
|
||||
|
||||
getAllResponseHeaders(): ?string {
|
||||
@@ -108,10 +190,6 @@ class XMLHttpRequestBase {
|
||||
throw new Error('Subclass must define sendImpl method');
|
||||
}
|
||||
|
||||
abortImpl(): void {
|
||||
throw new Error('Subclass must define abortImpl method');
|
||||
}
|
||||
|
||||
send(data: any): void {
|
||||
if (this.readyState !== this.OPENED) {
|
||||
throw new Error('Request has not been opened');
|
||||
@@ -125,7 +203,10 @@ class XMLHttpRequestBase {
|
||||
|
||||
abort(): void {
|
||||
this._aborted = true;
|
||||
this.abortImpl();
|
||||
if (this._requestId) {
|
||||
console.log('calling abort', this._requestId);
|
||||
RCTNetworking.abortRequest(this._requestId);
|
||||
}
|
||||
// only call onreadystatechange if there is something to abort,
|
||||
// below logic is per spec
|
||||
if (!(this.readyState === this.UNSENT ||
|
||||
@@ -138,16 +219,6 @@ class XMLHttpRequestBase {
|
||||
this._reset();
|
||||
}
|
||||
|
||||
callback(status: number, responseHeaders: ?Object, responseText: string): void {
|
||||
if (this._aborted) {
|
||||
return;
|
||||
}
|
||||
this.status = status;
|
||||
this.setResponseHeaders(responseHeaders || {});
|
||||
this.responseText = responseText;
|
||||
this.setReadyState(this.DONE);
|
||||
}
|
||||
|
||||
setResponseHeaders(responseHeaders: ?Object): void {
|
||||
this.responseHeaders = responseHeaders || null;
|
||||
var headers = responseHeaders || {};
|
||||
|
||||
Reference in New Issue
Block a user