Angulars $http.jsonp() is returning 404 [duplicate] - javascript

I am trying to obtain a .json file from remote firebase server.
function fetchData(remoteJsonId){
var url = "https://myAppName.firebaseapp.com/topics/"+remoteJsonID;
console.log(url); //This variable expands to the full domain name which is valid and returns success both on wget and the browser
$http.jsonp(url).then(
function(resp){
},
function(err){
console.log(err.status) // This posts "404" on console.
}
);
}
But If I open url in the browser the json file loads. Even if I wget url the json file loads. But through angular it returns a 404 not found.
Now the .json remote file has this structure:
[
{
"hello":"Europe"
},
{
"hello":"USA"
}
]
The above file can be fetched using $http.get() but not with $http.jsonp(). JSONP cant parse .json file with the above structure. How can I work around this?

You need to specify a ?callback=JSON_CALLBACK in the URL that you pass to $http.jsonp.
From Angular's $http.jsonp documentation:
jsonp(url, [config]);
Shortcut method to perform JSONP request.
Parameters
Param Type Details
url string
Relative or absolute URL specifying the destination of the request.
The name of the callback should be the string JSON_CALLBACK.
That last line is what you're missing.
A simple example (using a Firebase database, not Firebase hosting):
var app = angular.module('myapp', []);
app.controller('mycontroller', function($scope, $http) {
var url = 'https://yourfirebase.firebaseio.com/25564200.json';
$http.jsonp(url+'?callback=JSON_CALLBACK').then(
function(resp){
console.log(resp.data); // your object is in resp.data
},
function(err){
console.error(err.status)
}
);
});
In case you want to see it working: http://jsbin.com/robono/1/watch?js,console

Related

Chrome Extension Redirect to Local Page with POST Request

I am building a browser extension where I try to redirect a browser request to my page with a fair amount of data that will be contained in a JSON array returned from a service I call based on the requested URL. For example, if the user goes to example.com, I have a chrome.webRequest.onBeforeRequest.addListener that intercepts it based on the urls filter, invokes a AWS API Gateway endpoint that responds with a list of things in a JSON object. I need my local page to display that list of things in a local page.
I can show some small things by invoking the local page with URL parameters (and then treat it like a GET request), but this won't work for the amount of data i want to pass. How do I create a POST request for the redirect URL?
OR, is there some other pattern I should be using to do this?
listener code:
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if(swenToggle) {
return { redirectUrl: chrome.extension.getURL("markup/simple.html?r=n&url=" + details.url) }; // This is fine for simple data
} else {
//get the base URL
var baseUrl = new URL(details.url).hostname.split(".").slice(-2).join(".")
var apiUrl = // Call AWS API here
fetch(apiUrl).then(r => r.json()).then(result => {
console.log('RESULT : ' + result.body); // I need to pass this body to the redirectUrl below...
})
return { redirectUrl: chrome.extension.getURL("markup/complex.html?sourceUrl=" + baseUrl) };
}
},
{ urls: "example.com"},
["blocking"]
);
Solved it with a slightly different approach. Instead of calling the AWS API from background.js, I pass the parameters needed for the API call to complex.html as URL params, and then invoke the AWS API in complex.html.

How to return string as a response to http request

In my Maven app I have mapped put http request onto this function(using spring framework), and I want to check something inside it and send response as text. Then I want to send that request from angularjs and store that response into some variable from angularjs controller. This is what I have tried.
#RequestMapping(path="/play", method={RequestMethod.POST}, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public String someFunction(){
//...
return "some text";
}
$scope.getResponse = function(param1, param2...){
$http.post("url..").then(
function(response){
$scope.response = response.data.response;
console.info('success');
},
function(response){
console.info('failure');
})
}
Http is mapped correctly and works from browser, problem is how to store textual response into some angularjs variable from controller.
It seems $http finds it difficult to parse the invalid JSON data in the response.
We have produces = {MediaType.APPLICATION_JSON_UTF8_VALUE} in there for the API and sending out plain text. That's why it goes to the failure handler.
Change the media type to MediaType.TEXT_PLAIN_VALUE and see if it works...

Download Remote File With Angular Using $http.get() - OAuth Authentication

My users have private files that need to be downloaded by an authenticated users. My server first downloads a file from S3 using it's own S3 app_id/secret_token credentials. The downloaded file is then constructed and sent to the client using Rails' send_data method.
Ruby (on Rails):
# documents_controller.rb
def download
some_file = SomeFile.find(params[:id])
# download file from AWS S3 to server
data = open(some_file.document.url)
# construct and send downloaded file to client
send_data data.read, filename: some_file.document_identifier, disposition: 'inline', stream: 'true'
end
Originally, I wanted to do trigger the download directly from the HTML template.
HTML:
<!-- download-template.html -->
<a target="_self" ng-href="{{ document.download_url }}" download="{{document.file_name}}">Download</a>
Looks simple enough but the problem is that Angular's $http interceptor doesn't catch this type of external link click and therefore the appropriate headers are not appended for server-side authentication. The result is a 401 Unauthorized Error.
Instead, I need to trigger the download using ng-click and then performing an $http.get() request from the angular controller.
HTML:
<!-- download-template.html -->
<div ng-controller="DocumentCtrl">
<a ng-click="download(document)">Download</a>
</div>
Javascript:
// DocumentCtrl.js
module.controller( "DocumentCtrl",
[ "$http", "$scope", "FileSaver", "Blob",
function( $http, $scope, FileSaver, Blob ) {
$scope.download = function( document ) {
$http.get(document.download_url, {}, { responseType: "arraybuffer" } )
.success( function( data ) {
var blob = new Blob([data], { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" });
FileSaver.saveAs(blob, document.file_name);
});
};
}]);
FileSaver is a simple library to save files using Blobs (on the client, obviously).
This gets me passed by my authentication problem but results in the file being saved/download to the client in an unreadable/unusable format.
Why is the file being downloaded in an unusable format?
Thanks in advance.
Angular's $http method needs to be configured to accept a binary data response.
Rails' send_data documentation:
Sends the given binary data to the browser. This method is similar to
render plain: data, but also allows you to specify whether the browser
should display the response as a file attachment (i.e. in a download
dialog) or as inline data. You may also set the content type, the
apparent file name, and other things.
Angular's $http documentation is very poor regarding $http's configuration of responseType. Essentially, $http needs to be told to expect a binary data response by setting responseType to "arraybuffer" (see below).
$scope.download = function( document ) {
console.log("download: ", document);
$http({
url: document.download_url,
method: "GET",
headers: {
"Content-type": "application/json"
},
responseType: "arraybuffer" // expect to handle binary data response
}).success( function( data, status, headers ) {
var type = headers('Content-Type');
var blob = new Blob([data], { type: type });
FileSaver.saveAs(blob, document.file_name);
});
};
Angular's $http documentation could be a little more descriptive than:
Usage
$http(config);
Arguments
config
responseType - {string} - see XMLHttpRequest.responseType.
Hi I have an example of how I download a file from my server with angular:
I call the file with GET request:
file download html(client side):
<a ng-href="/api/downloadFile/{{download.id}}" type="submit" class="btn btn-primary col-lg-12 btn-modal-costume" >download</a>
file download java(server side):
public static Result download(String id) {
String content = null;
for (controllers.file file : files) {
if (file.getId().equals(id)){
content = file.getContent();
}
}
return ok(new java.io.File("/temp/" + id+ "file" + content)).as("application/force-download");
}
If you like you can see the all code in my github project
I think you were on the right track with the javascript solution, but just had a typo. In the $http.get call you pass an empty object as the second parameter. This is where the options argument with {responseType: arraybuffer} should have gone. See docs for $http.get here:
https://docs.angularjs.org/api/ng/service/$http#get

Configure Grails controller to download file in browser after retrieving data from service

My controller in Grails first fetches the data from a remote service API, and the returned data is a String. Then I would like to have the data downloaded as a csv file in the browser. I came across a similar post on SO and stole the code for using the response as below:
String exportResults = dataService.getDataFromService()
response.setHeader "Content-disposition", "attachment; filename=data_export.csv"
response.contentType = 'text/csv'
response.outputStream << exportResults.getBytes() //getBytes() not portable
response.outputStream.flush()
But this does not trigger any download window in the browser. I was wondering why. I use AngularJS to make a POST request to the controller and resolve the promise as below (JavaScript code):
ExportService.exportData(some_params).then(function(data) {
$log.info('export promise resolved: ');
//window.open(data, '_blank', ''); //not working
}).catch(function(err) {
$scope.message = "failed to retrieve data from export service";
$log.error(err);
}).finally(function(complete) {
$scope.message = "Data export completed.";
});
You need to replace 'text/csv' with 'application/octet-stream' for response.contentType. The content type 'application/octet-stream' is used for a binary file.
Try adding this after response.outputStream.flush() and see if it works.
webRequest.renderView = false
You can even try looking here.

Angularjs $resource url intercept url encoding

I'm working on a sort of file-manager application that connects to a RESTFUL file api.
On the angular app, each file and directory is an instance of angular $resource using the file-object property relativePathName as resource id .
js
var File = $resource(url + '/:type/:id', {id: '#relativePathName', type: '#type'}, {…});
The problem is, when updating a file resource, the relativePathName parameter gets url encoded, e.g. / becomes %2F which causes the server to intercept the request before it hits the actual API (I assume the server treats this as a physical address and of returns a 404 response). The API is capable of treating whole url segments as a single param, so basically it'd treat path/to/file as a uri parameter of http://myapp.com/api/files/create/path/to/file and not as a different uri.
My question is, is there a way to modify the request url after it's being generated by the private Router instance inside of the resource constructor? If so, how (found nothing on this in the docs)?. What would be a possible solution? passing relativePathName as a parameter instead of declaring it as the resource id (which would require modifying the API)?
Thanks in advance.
Thomas
Using $resource is not the one stop shop for RESTful service calls, it is merely a convenience service for api's that are structured in a certain way. If $resource cannot do what you need, just create your own service using a mix of $resource and $http that that fits the api you are trying to call.
In our app we wanted a different URL for getByName requests, so we override the resource address with the URL parameter of the action getByName like so:
myapp.factory('ListGroup', ['$resource',
function($resource) {
return $resource(
'/API/List/:Id',
{
Id:'#Id',
Name:'#Name'
},
{
getByName: {method: 'GET', url: '/API/List/Group/:Name', isArray: true}
}
);
}
]);
My question is, is there a way to modify the request url after it's being generated by the private Router instance inside of the resource constructor?
I'm not sure about inside of the resource constructor but you can use interceptors to programatically alter route urls after they have been generated by $resource.
structure
hooks.config.js
hooks.factory.js
hooks.module.js
hooks.module.js
module.exports = angular
.module("app.hooks", [])
.factory("hooks", require("./hooks.factory.js"))
.config(require("./hooks.config.js"));
hooks.config.js
module.exports = ["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push("hooks");
}];
hooks.factory.js
module.exports = ["$q", "$location", function($q, $location) {
var basePrefix = "/api/v1";
return {
//invoked on every http request
request: function(request) {
request.url = interpret(request.url);
return $q.when(request);
}
};
function interpret(str) {
//if requesting an html template, don't do anything
if (str.indexOf(".html") > -1)
return str;
//if you're accessing the api, append the base prefix globally here
else
return basePrefix + str;
}
}];

Categories