MOBILE-2253 core: Implement HTTP interceptor for WS calls

main
Dani Palou 2017-11-27 09:51:15 +01:00
parent ab1d72780e
commit a4adffe94d
4 changed files with 89 additions and 43 deletions

View File

@ -15,7 +15,7 @@
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core'; import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule, Platform } from 'ionic-angular'; import { IonicApp, IonicErrorHandler, IonicModule, Platform } from 'ionic-angular';
import { HttpClient, HttpClientModule } from '@angular/common/http'; import { HttpClient, HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { SplashScreen } from '@ionic-native/splash-screen'; import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar'; import { StatusBar } from '@ionic-native/status-bar';
@ -25,6 +25,7 @@ import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { MyApp } from './app.component'; import { MyApp } from './app.component';
import { CoreInterceptor } from '../classes/interceptor';
import { CoreLoggerProvider } from '../providers/logger'; import { CoreLoggerProvider } from '../providers/logger';
import { CoreDbProvider } from '../providers/db'; import { CoreDbProvider } from '../providers/db';
import { CoreAppProvider } from '../providers/app'; import { CoreAppProvider } from '../providers/app';
@ -80,6 +81,11 @@ export function createTranslateLoader(http: HttpClient) {
MyApp MyApp
], ],
providers: [ providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: CoreInterceptor,
multi: true,
},
StatusBar, StatusBar,
SplashScreen, SplashScreen,
SQLite, SQLite,

View File

@ -0,0 +1,79 @@
// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
/**
* Interceptor for Http calls. Adds the header 'Content-Type'='application/x-www-form-urlencoded'
* and serializes the parameters if needed.
*/
@Injectable()
export class CoreInterceptor implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
// Add the header and serialize the body if needed.
const newReq = req.clone({
headers: req.headers.set('Content-Type', 'application/x-www-form-urlencoded'),
body: typeof req.body == 'object' && String(req.body) != '[object File]' ?
CoreInterceptor.serialize(req.body) : req.body
});
// Pass on the cloned request instead of the original request.
return next.handle(newReq);
}
/**
* Serialize an object to be used in a request.
*
* @param {any} obj Object to serialize.
* @param {boolean} [addNull] Add null values to the serialized as empty parameters.
* @return {string} Serialization of the object.
*/
public static serialize(obj: any, addNull?: boolean) : string {
let query = '',
fullSubName,
subValue,
innerObj;
for (let name in obj) {
let value = obj[name];
if (value instanceof Array) {
for (let i = 0; i < value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += this.serialize(innerObj) + '&';
}
} else if (value instanceof Object) {
for (let subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += this.serialize(innerObj) + '&';
}
} else if (addNull || (typeof value != 'undefined' && value !== null)) {
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
}
return query.length ? query.substr(0, query.length - 1) : query;
}
}

View File

@ -1036,46 +1036,6 @@ export class CoreUtilsProvider {
return value1 === value2; return value1 === value2;
} }
/**
* Serialize an object to be used in a request.
*
* @param {any} obj Object to serialize.
* @param {boolean} [addNull] Add null values to the serialized as empty parameters.
* @return {string} Serialization of the object.
*/
serialize(obj: any, addNull?: boolean) : string {
let query = '',
fullSubName,
subValue,
innerObj;
for (let name in obj) {
let value = obj[name];
if (value instanceof Array) {
for (let i = 0; i < value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += this.serialize(innerObj) + '&';
}
} else if (value instanceof Object) {
for (let subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += this.serialize(innerObj) + '&';
}
} else if (addNull || (typeof value != 'undefined' && value !== null)) {
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
}
return query.length ? query.substr(0, query.length - 1) : query;
}
/** /**
* Stringify an object, sorting the properties. It doesn't sort arrays, only object properties. E.g.: * Stringify an object, sorting the properties. It doesn't sort arrays, only object properties. E.g.:
* {b: 2, a: 1} -> '{"a":1,"b":2}' * {b: 2, a: 1} -> '{"a":1,"b":2}'

View File

@ -24,6 +24,7 @@ import { CoreTextUtilsProvider } from './utils/text';
import { CoreUtilsProvider } from './utils/utils'; import { CoreUtilsProvider } from './utils/utils';
import { CoreConstants } from '../core/constants'; import { CoreConstants } from '../core/constants';
import { Md5 } from 'ts-md5/dist/md5'; import { Md5 } from 'ts-md5/dist/md5';
import { CoreInterceptor } from '../classes/interceptor';
/** /**
* Interface of the presets accepted by the WS call. * Interface of the presets accepted by the WS call.
@ -416,7 +417,7 @@ export class CoreWSProvider {
*/ */
protected getQueueItemId(method: string, url: string, params?: any) : string { protected getQueueItemId(method: string, url: string, params?: any) : string {
if (params) { if (params) {
url += '###' + this.utils.serialize(params); url += '###' + CoreInterceptor.serialize(params);
} }
return method + '#' + Md5.hashAsciiStr(url); return method + '#' + Md5.hashAsciiStr(url);
} }
@ -595,7 +596,7 @@ export class CoreWSProvider {
siteUrl = preSets.siteUrl + '/webservice/rest/server.php?moodlewsrestformat=json'; siteUrl = preSets.siteUrl + '/webservice/rest/server.php?moodlewsrestformat=json';
// Serialize data. // Serialize data.
data = this.utils.serialize(data); data = CoreInterceptor.serialize(data);
// Perform sync request using XMLHttpRequest. // Perform sync request using XMLHttpRequest.
xhr = new (<any>window).XMLHttpRequest(); xhr = new (<any>window).XMLHttpRequest();