Skip to content

Commit

Permalink
feat(ios,android): add request duration in fetch response header
Browse files Browse the repository at this point in the history
  • Loading branch information
wwwcg committed Jul 12, 2024
1 parent a7dcbdb commit 64e85a1
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
public class NetworkModule extends HippyNativeModuleBase {

private static final String TAG = "NetworkModule";
private static final String HTTP_RESPONSE_REQUEST_DURATION = "Hippy-Request-Duration";

public NetworkModule(HippyEngineContext context) {
super(context);
Expand Down Expand Up @@ -103,8 +104,9 @@ protected void normalizeRequest(@NonNull HippyMap request,
}

@NonNull
protected JSObject handleFetchResponse(@NonNull ResourceDataHolder dataHolder)
throws IllegalStateException {
protected JSObject handleFetchResponse(@NonNull ResourceDataHolder dataHolder,
double requestDuration)
throws IllegalStateException {
JSObject responseObject = new JSObject();
int statusCode = -1;
String responseMessage = null;
Expand All @@ -129,6 +131,7 @@ protected JSObject handleFetchResponse(@NonNull ResourceDataHolder dataHolder)
if (responseMessage == null) {
responseMessage = (dataHolder.errorMessage == null) ? "" : dataHolder.errorMessage;
}
headerObject.set(HTTP_RESPONSE_REQUEST_DURATION, Double.toString(requestDuration));
responseObject.set(HTTP_RESPONSE_STATUS_CODE, statusCode);
responseObject.set("statusLine", responseMessage);
responseObject.set("respHeaders", headerObject);
Expand All @@ -145,10 +148,12 @@ protected JSObject handleFetchResponse(@NonNull ResourceDataHolder dataHolder)
return responseObject;
}

protected void handleFetchResult(@NonNull ResourceDataHolder dataHolder, final Promise promise) {
protected void handleFetchResult(@NonNull ResourceDataHolder dataHolder,
double requestDuration,
final Promise promise) {
try {
if (dataHolder.resultCode == ResourceDataHolder.RESOURCE_LOAD_SUCCESS_CODE) {
JSObject responseObject = handleFetchResponse(dataHolder);
JSObject responseObject = handleFetchResponse(dataHolder, requestDuration);
promise.resolve(responseObject);
} else {
String errorMessage =
Expand Down Expand Up @@ -177,19 +182,25 @@ public void fetch(final HippyMap request, final Promise promise) {
promise.reject("Get url parameter failed!");
return;
}

// Record request start time
final long startTime = System.nanoTime();

vfsManager.fetchResourceAsync(uri, requestHeaders, requestParams,
new FetchResourceCallback() {
@Override
public void onFetchCompleted(@NonNull ResourceDataHolder dataHolder) {
handleFetchResult(dataHolder, promise);
dataHolder.recycle();
}
new FetchResourceCallback() {
@Override
public void onFetchCompleted(@NonNull ResourceDataHolder dataHolder) {
// Time taken for the request, in milliseconds
double requestDuration = (System.nanoTime() - startTime) / 1_000_000.0;
handleFetchResult(dataHolder, requestDuration, promise);
dataHolder.recycle();
}

@Override
public void onFetchProgress(long total, long loaded) {
// Nothing need to do here.
}
});
@Override
public void onFetchProgress(long total, long loaded) {
// Nothing need to do here.
}
});
}

@HippyMethod(name = "getCookie")
Expand Down
2 changes: 1 addition & 1 deletion framework/ios/module/network/HippyNetWork.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
*/

#import <Foundation/Foundation.h>

#import "HippyBridgeModule.h"

/// Hippy Network module
@interface HippyNetWork : NSObject <HippyBridgeModule, NSURLSessionDataDelegate>

@end
90 changes: 68 additions & 22 deletions framework/ios/module/network/HippyNetWork.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,31 @@
* limitations under the License.
*/

#import <WebKit/WKHTTPCookieStore.h>
#import <WebKit/WKWebsiteDataStore.h>

#import "HippyNetWork.h"
#import <WebKit/WebKit.h>
#import <QuartzCore/QuartzCore.h>
#import "HippyBridge+VFSLoader.h"
#import "HippyDefines.h"
#import "HippyNetWork.h"
#import "HippyAssert.h"
#import "HippyUtils.h"


// Request parameter of fetch API
static NSString *const kHippyNetworkRequestParaURL = @"url";
static NSString *const kHippyNetworkRequestParaMethod = @"method";
static NSString *const kHippyNetworkRequestParaHeaders = @"headers";
static NSString *const kHippyNetworkRequestParaBody = @"body";

// Response parameter of fetch API
static NSString *const kHippyNetworkResponseStatusCode = @"statusCode";
static NSString *const kHippyNetworkResponseStatusLine = @"statusLine";
static NSString *const kHippyNetworkResponseHeaders = @"respHeaders";
static NSString *const kHippyNetworkResponseBody = @"respBody";

// Duration parameter in resp.header of fetch API
static NSString *const kHippyNetworkRequestDuration = @"Hippy-Request-Duration";


static NSStringEncoding GetStringEncodingFromURLResponse(NSURLResponse *response) {
NSString *textEncoding = [response textEncodingName];
if (!textEncoding) {
Expand All @@ -45,35 +61,51 @@ @implementation HippyNetWork

HIPPY_EXPORT_MODULE(network)

HIPPY_EXPORT_METHOD(fetch:(NSDictionary *)params resolver:(__unused HippyPromiseResolveBlock)resolve rejecter:(__unused HippyPromiseRejectBlock)reject) {
HIPPY_EXPORT_METHOD(fetch:(NSDictionary *)params
resolver:(HippyPromiseResolveBlock)resolve
rejecter:(HippyPromiseRejectBlock)reject) {
if (!resolve) {
return;
}
NSString *method = params[@"method"];
NSString *url = params[@"url"];
NSDictionary *header = params[@"headers"];
NSString *body = params[@"body"];

HippyAssertParam(url);
HippyAssertParam(method);

NSString *url = params[kHippyNetworkRequestParaURL];
NSString *method = params[kHippyNetworkRequestParaMethod];
NSDictionary *header = params[kHippyNetworkRequestParaHeaders];
NSString *body = params[kHippyNetworkRequestParaBody];

if (!url) {
HippyAssertParam(url);
if (reject) {
reject(@"invalid_params", @"URL is missing", nil);
}
return;
}

NSMutableDictionary *vfsParams = [NSMutableDictionary new];
[header enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, __unused BOOL *stop) {
[header enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL *stop) {
NSString *value = nil;
if ([obj isKindOfClass: [NSArray class]]) {
if ([obj isKindOfClass:[NSArray class]]) {
value = [[(NSArray *)obj valueForKey:@"description"] componentsJoinedByString:@","];
} else if ([obj isKindOfClass: [NSString class]]) {
} else if ([obj isKindOfClass:[NSString class]]) {
value = obj;
}

[vfsParams setValue: value forKey: key];
if (value) {
[vfsParams setValue:value forKey:key];
}
}];

NSData *data = nil;
if (body) {
data = [body dataUsingEncoding:NSUTF8StringEncoding];
}

// Record request start time
CFTimeInterval startTime = CACurrentMediaTime();

// Send Request
[self.bridge loadContentsAsynchronouslyFromUrl:url
method:method?:@"Get"
method:method ?: @"GET"
params:vfsParams
body:data
queue:nil
Expand All @@ -83,19 +115,33 @@ @implementation HippyNetWork
NSStringEncoding encoding = GetStringEncodingFromURLResponse(response);
NSString *dataStr = [[NSString alloc] initWithData:data encoding:encoding];
NSUInteger statusCode = 0;
NSDictionary *headers = nil;
NSMutableDictionary *headers = [NSMutableDictionary dictionary];

if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpRes = (NSHTTPURLResponse *)response;
statusCode = [httpRes statusCode];
headers = [httpRes allHeaderFields];
[headers addEntriesFromDictionary:[httpRes allHeaderFields]];
}
NSDictionary *result =
@{ @"statusCode": @(statusCode), @"statusLine": @"", @"respHeaders": headers ?: @ {}, @"respBody": dataStr ?: @"" };

// Get request duration,in ms.
// and add to resp headers.
CFTimeInterval requestDuration = (CACurrentMediaTime() - startTime) * 1000;
[headers addEntriesFromDictionary:@{ kHippyNetworkRequestDuration : @(requestDuration).stringValue }];

NSDictionary *result = @{
kHippyNetworkResponseStatusCode : @(statusCode),
kHippyNetworkResponseStatusLine : @"",
kHippyNetworkResponseHeaders : headers ?: @{},
kHippyNetworkResponseBody : dataStr ?: @""
};

resolve(result);
}];
}

HIPPY_EXPORT_METHOD(getCookie:(NSString *)urlString resolver:(HippyPromiseResolveBlock)resolve rejecter:(__unused HippyPromiseRejectBlock)reject) {
HIPPY_EXPORT_METHOD(getCookie:(NSString *)urlString
resolver:(HippyPromiseResolveBlock)resolve
rejecter:(__unused HippyPromiseRejectBlock)reject) {
NSData *uriData = [urlString dataUsingEncoding:NSUTF8StringEncoding];
if (nil == uriData) {
resolve(@"");
Expand Down

0 comments on commit 64e85a1

Please sign in to comment.