$http.get pass encodeURIComponent to Web API - angularjs

I want to pass some special characters( _ + - ) to my web api, now I know I have to use encodeURIComponent() in javascript which does encode them. But when I pass the encoded url to http.get it is throwing an exception:
The get request code:
find: function (id) {
var scope = this;
var urlApi = webapi_base_url + model_url;
id = encodeURIComponent(id);
return $http.get(urlApi + id)
.then(function (response) {
if (response.data.success && response.data.exists) {
//logger.info('Successfully found model', '', 'Success');
}
else {
if (showLogger)
logger.error(response.data.error, '', 'Error');
}
return response.data;
})
.catch(function (err) {
scope.WebFailed('get', err);
})
}
For example I want to pass the values a+ to my web api, the url is:
https://localhost:44310/api/v1/model/a%26
The following error is thrown:
XMLHttpRequest cannot load https://localhost:44310/api/v1/model/a%26. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:59242' is therefore not allowed access. The response had HTTP status code 400.
When I send the value of 'a' to the web API it is fine and no problems:
The web api code
[Route("{description}")]
public async Task<IHttpActionResult> Get([FromUri] string description)
{
Model model = await _repository.Model().Get().Where(x => x.Description == description).FirstOrDefaultAsync();
if (model == null)
return Ok(new { success = false, exists = false, error = "Could not find model" });
return Ok(new { success = true, exists = true });
}
I think when I have encoded the uri the web api cannot find the path and is throwing an exception.
Any ideas how I can fix the web api to allow encoded characters.
Thanks

Related

How to send an HTTP GET request using Firebase and Angular?

My app uses IBM Watson Speech-to-Text, which requires an access token. From the command line I can get the access token with curl:
curl -X GET --user my-user-account:password \
--output token \
"https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api"
When I make an HTTP request using Angular's $http service I get a CORS error:
var data = {
user: 'my-user-account:password',
output: 'token'
};
$http({
method: 'GET',
url: 'https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api',
data: data,
}).then(function successCallback(response) {
console.log("HTTP GET successful");
}, function errorCallback(response) {
console.log("HTTP GET failed");
});
The error message says:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:8080' is therefore not allowed
access. The response had HTTP status code 401.
As I understand, it's not possible to do CORS from Angular; CORS has to be done from the server. I know how to do CORS with Node but I'm using Firebase as the server.
Firebase has documentation about making HTTP requests with CORS. The documentation says to write this:
$scope.getIBMToken = functions.https.onRequest((req, res) => {
cors(req, res, () => {
});
});
First, that doesn't work. The error message is functions is not defined. Apparently functions isn't in the Firebase library? I call Firebase from index.html:
<script src="https://www.gstatic.com/firebasejs/4.3.0/firebase.js"></script>
My controller injects dependencies for $firebaseArray, $firebaseAuth, and $firebaseStorage. Do I need to inject a dependency for $firebaseHttp or something like that?
Second, how do I specify the method ('GET'), the URL, and the data (my account and password)?
if you want to send credentials with angular, just set withCredentials=true. I am also using CORS with Angular v4, for your HTTP header error, you are right. Header Access-Control-Allow-Origin must be added on server side, check if you have settings in your api to allow certain domains, urls, pages, because google api's has this function, so check where you get token there should be some settings.
Here is example, how I am calling API with CORS, using typescript:
broadcastPresense(clientId: string) {
const headers = new Headers({'Content-Type':'application/json','withCredentials':'true'});
return this.http.post('http://localhost/api.php',
{
'jsonrpc': '2.0',
'method': 'somemethod',
'params': {'client_id': clientId},
'id': CommonClass.generateRandomString(16)
},{headers: headers, withCredentials:true}).map(
(res: Response) => {
console.log(res);
const data = res.json();
console.log(data);
if (data.error == null) {
return data.result;
} else if (data.error != null) {
throw data.error;
}
throw data.error;
}
).catch(
(error) => {
this.router.navigate(['/error',3],{queryParams: {desc:'Server error'}});
return Observable.throw(error);
}
);
}
Hope it helps :)
The answer is to use Cloud Functions for Firebase, which enable running Node functions from the server. Then you use the Node module request to send the HTTP request from Node.

Custom error message with content-type response

I'm trying to implement some error handling into my MCV AngularJS application, but came across this one issue that I'm not sure how to solve.
Structure
In my AngularJS service ticketService I have the following method:
this.downloadFile = function (fileId) {
return $http.get(baseUrl + "/Downloadfile/" + fileId, { responseType: "blob" });
}
And in my controller:
$scope.downloadFile = function (fileId) {
ticketService.downloadFile(fileId)
.then(function (response) {
// Handle correct request and response
}, function (err) {
// Handle error
notify({ message: "Something went wrong: " + err.data.Message, position: "center", duration: 10000 });
})
}
Here's what I return from the backend MVC Web API method:
var error = new HttpError("Failed to find file, bla bla bla.");
return Request.CreateResponse(HttpStatusCode.NotFound, error);
Problem
My issue is that since my responseType is set to be blob, my err object is the same response type. I would believe that it should be possible for my backend service to override this response type, and respond with an object that contains some Message.
From this response, I would've thought that I could get err.data.Message, but perhaps I misunderstood this scenario?
Thank you in advance.
public HttpResponseMessage Get(int id)
{
try
{
return Request.CreateResponse(HttpStatusCode.OK, new { Status =
"OK", Message = this._myContext.GetCustomer(id) });
}
catch(Exception e)
{
return Request.CreateResponse(HttpStatusCode.Conflict, new {
Status = "NO", Message = e.ToString() });
}
}
You can return any message like "Failed to find file, bla bla bla." in Message. Then you just need to check in ajax success method like data.Message,
The $http service uses the XHR API which is not capable of changing the responseType on the fly.
You can set the status message and use that:
public ActionResult Foo()
{
Response.StatusCode = 403;
Response.StatusDescription = "Some custom message";
return View(); // or Content(), Json(), etc
}
Then in AngularJS:
$scope.downloadFile = function (fileId) {
return ticketService.downloadFile(fileId)
.then(function (response) {
// Handle correct request and response
return response.data;
}).catch(function (response) {
// Handle error
console.log(response.status);
console.log(response.statusText);
throw response;
});
};
Alternative approaches are:
Use the Fetch API which has a more powerful and flexible feature set.
Use the FileReader API and JSONparse() method to convert the Blob to a JavaScript Object.

How to use these 2 rest services in AngularJS, also how to call requrest for jwt from spring backend

I am trying to consume rest services but don't know how to call web services in angularjs from spring backend, also want to know how to integrage json web based token which I have written in spring backend in angularjs.
Webservice 1 : Login for admin
URL: <http://200.201.4.12:8080/liberary/authenticateUser>
Request type: POST
Header type: Content-Type application/json
Parameters: {
"username":"darek",
"password":"dark99"
}
Webservice 1 : Login for user
URL: <http://200.201.4.12:8080/liberary/authenticateUser>
Request type: POST
Header type: Content-Type application/json
Parameters: {
"username":"polo",
"password":"polo33"
}
My Code is:
authService.login = function(user, success, error) {
$http.post('misc/users.json').success(function(data) {
//this is my dummy technique, normally here the
//user is returned with his data from the db
var users = data.users;
if(users[user.username]){
var loginData = users[user.username];
//insert your custom login function here
if (user.username == loginData.username && user.password == loginData.username) {
//set the browser session, to avoid relogin on refresh
$window.sessionStorage["userInfo"] = JSON.stringify(loginData);
//delete password not to be seen clientside
delete loginData.password;
//update current user into the Session service or $rootScope.currentUser
//whatever you prefer
Session.create(loginData);
//or
$rootScope.currentUser = loginData;
//fire event of successful login
$rootScope.$broadcast(AUTH_EVENTS.loginSuccess);
//run success function
success(loginData);
} else {
//OR ELSE
//unsuccessful login, fire login failed event for
//the according functions to run
$rootScope.$broadcast(AUTH_EVENTS.loginFailed);
error();
}
}
});
};
You are using $http.post with a json file (Do not know where it comes from
You should replace it with the URL of your webservice + the data
$http.post('http://200.201.4.12:8080/liberary/authenticateUser',
{"username" : "polo", "password" : dark99}).then(function(data){
//Do what you want with the data returned from your webservice
}, function(error){
//Handle error
});
NOTE : You only have 1 webservice which is located on 200.201.4.12:8080

I send http post request with angular but it does not go to the asp.net mvc action and returns html layout tags

I am doing an angular application with asp.net mvc and i made a registration form with identity, I have layout and index mvc view which i just write in it ng-view tag and i inject html pages in it, I am doing a http post request from angular controller to mvc action method but the request does not go to the mvc action, whereas when i change th views to mvc views and make a templateUrl in angular map to mvc method it works well.
Can any one help me in this problem.
[HttpPost]
[AllowAnonymous]
public async Task<JsonResult> Register(RegisterViewModel model)
{
string message = "";
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
FirstName = model.FirstName,
MiddleName = model.MiddleName,
LastName = model.LastName,
UserName = model.Email,
Email = model.Email,
UserStatus = UserStatus.Waiting
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
message = "Success";
}
else
{
AddErrors(result);
message = "InvalidEmail";
}
}
else
{
message = "Failed!";
}
return new JsonResult { Data = message, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
and this is my angular controller
MyApp.controller('RegisterController', ['$scope','$http',function ($scope, $http) {
$scope.message = '';
$scope.isFormValid = false;
//Check Form Validation
$scope.$watch('f1.$valid', function (newValue) {
$scope.isFormValid = newValue;
});
//Save Data
$scope.SaveData = function (data) {
$scope.submitted = true;
$scope.message = '';
if ($scope.isFormValid) {
$http({
method: 'POST',
url: '/Account/Register',
data: data
}).then(function (response) {
// check your response (if a success status code was resolved)
console.log(response.data);
}, function (error) {
// check your error response
console.log(error);
});
} else {
$scope.message = "Please Fill the blanks";
}
}
}]);
and this is my html page:
<div ng-controller="RegisterController">
<form name="f1" ng-submit="SaveData(user)" novalidate>
controls here
</form
1) Check your browser console for any javascript errors, if you have any, resolve them and try again!
2) Check you have the correct ActionMethodSelectorAttribute attribute ([HttpPost]) over your controller method and that your method name is spelt correctly.
3) Check that you have the correct path in your request.
4) Check you are sending the correct data to the controller!!!
5) Check that the method is public.
6) Check that you are authorised to access that controller/method.
7) Check that you don't have any duplicate method names with either, a) the same parameters and name (if your not using an ActionMethodSelectorAttribute, or b) the same names and method select attributes.
8) Remove all parameters from your method, put a breakpoint at the start of the method, and try making the request and see if it hits the breakpoint. If it works without parameters and not with, then you are not passing the correct required data into the method.
9) Make your request and check the response!! (example below):
// make your request
$http({
method: 'POST',
url: '/Controller/Method',
data: {
foo: bar
}
}).then(function(response) {
// check your response (if a success status code was resolved)
console.log(response);
}, function(error) {
// check your error response
console.log(error);
});
If you have a 404 then your method was not found, if you have a 500 then something blew up in your code, if you have a 401 then you are unauthorised etc... This is really useful to actually know what is going on with your request...
10) Check your application is running!

Fixing 3rd party API 'Access-Control-Allow-Origin' error

I have an Angular application, currently an HTML file I open but it will soon be converted to a server/accessed through localhost. I use $http to access a 3rd party API (I have no control over its responses; most of the API calls work, but some don't and throw the error:
XMLHttpRequest cannot load http://api.nal.usda.gov/ndb/search/?format=json&api_key=RJEnADgGbCjfJYi0z8vuVnelYXn2Smud2Dfi2u2F&q=susage. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 404.
The API calls that throw that error are the searches that return 0 results (in the example, the database returns no results for "susage"). In the Network tab, the response can't be loaded and no response headers are listed; for other working API calls, under Response Headers, the necessary "Access-Control-Allow-Origin:*" is present.
The API definitely forms a response and tries to send it back, but fails for whatever reason. Visiting the posted url shows that response.
Why do only the empty searches throw the error when API understands and has a response for both calls, and how do I fix it? I would prefer that my frontend communicates with the API directly, as opposed to communicating with my backend which in turn communicates with the API.
For comparison, a search with results (spelling 'sausage' correctly) vs a search without results: http://imgur.com/a/ihhI1
The $http code:
return $http.get('http://api.nal.usda.gov/ndb/search/?format=json', {
params: {
api_key: usdaKey,
q: query
}
})
In order to expose the "-1" status (timeout) to the UI, I changed the service method to simply return the promise, like this:
var search = function(query) {
return $http.get('http://api.nal.usda.gov/ndb/search/?format=json', {
params: {
api_key: usdaKey,
q: query
}
});
};
Then you can handle the error in your controller, like this:
$scope.search = function(query) {
$scope.items = [];
$scope.err = null;
foodInfo.search(query).then(function(response) {
console.log(response);
$scope.items = response.data.list.item;
}, function(e) {
console.log('Error status: ' + e.status);
if (e.status === -1) {
$scope.err = 'No data found';
}
});
};

Resources