I'm working on an app for a school project. I'm trying to fetch a string in react, the backend has been build with C#. In the backend i'm sending a HttpResponseMessage with StringContent to the client side. But i can't seem to read the StringContent at the client side.
The Api at server side:
[HttpGet("{id}")]
public async Task<HttpResponseMessage> downloadDocument(int id)
{
try
{
string base64String = await this.DocumentService.downloadDocument(id);
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StringContent(base64String);
return response;
}
catch (Exception ex)
{
var response = new HttpResponseMessage(HttpStatusCode.ExpectationFailed);
response.Content = new StringContent(ex.Message);
return response;
}
}
The Client side code
function downloadDocument(param: any) {
fetch(process.env.REACT_APP_API_URL + 'document/' + param.row.id, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
})
.then((response) => response.json())
.then((data) => {
console.log(data);
})
}
Where i log data to the console i get the following:
I can see the content object there. but how do i get the string i've added in the HttpResponseMessage with new StringContent(base64String);
Related
I am unable to fetch the query parameters of frontend GET request, on the backend side.
I tried using url and query. I need to fetch the query on the nodejs side.
Kindly suggest a suitable method that would help me get the details on GET request using axios.
code -
component.ts - angular file
googleSearch(googleText){
let params = new HttpParams();
params = params.append('q', googleText.trueLocation);
return new Promise((resolve, reject) => {
this.httpClient.get("http://localhost:3003/seekSearchApi" , ({params:params}))
.pipe(map(Response => Response))
.pipe(catchError(this.errorHandler))
.subscribe((res: Response) => {
this.writeItOutput = res;
resolve(this.writeItOutput);
});
})
}
errorHandler(error: HttpErrorResponse) {
return throwError(error.message || 'server Error');
}
}
server.js- express file
app.use('/seekSearchApi', require('./server/nodejs-serverapi'));
applicationserver.js - nodejs file
function seekSearchApi(req,res) {
var query = require('url').parse(req.url,true).query;
console.log("req.query.q", query.q); //no response
console.log("Inside seekSearchApi");
axios({
method: 'get',
url: 'https://serpapi.com/search.json?',
data: {
api_key: "xxxx",
q:query.q
hl: "en",
gl: "us",
google_domain: "google.com"
}
}).then((response) => {
res.send(stringify(response))
}, (error) => {
console.log(error);
});
I figured it out .
On node side.
applicationserver.js
function seekSearchApi(req,res) {
var url_data = url.parse(req.url, true);
var query = url_data.query;
var queryData= Object.assign({},query);
console.log("queryData = ", queryData);
::::
}
I am downloading a pdf file from API, but I am getting a blank PDF. I have tested the API endpoint and able to get the byte stream on the console and when I save it to File, it got saved and the file looks good. Getting the same response back to the front end using React and I could see the PDF byte stream in the response.
However, I could not see the content. It says the file is damaged or corrupted when I opened the downloaded PDF from my local.
I have looked at many examples and are following the same pattern, but I think I am missing something here.
My API Java endpoint definition looks like below
#GetMapping(value = "/fetchFile")
public ResponseEntity<byte[]> fetchFile(#RequestParam final String key) {
FileResponse response = myService.readFile(key);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + key.substring(key.lastIndexOf('/') + 1) + "\"");
return Mono.just(ResponseEntity.ok().headers(httpHeaders).contentLength(response.getContentLength())
.contentType(MediaType.parseMediaType(response.getContentType()))
.body(response.getResponseBytes()));
}
Frontend:
rounterFetchFile.js
router.get('/', (request, resp) => {
axios({
method: 'get',
baseURL: 'http://mybackend.apibase.url',
responseType: 'blob',
url: '/fetchFile',
params: {
fileKey: 'myfile.pdf'
}
})
.then(response => {
return resp.send(response.data)
})
.catch(error => {
console.error(error)
return resp.status(error.response.status).end()
})
})
in myFileComoponent.js
//a function that reads the response from rounterFetchFile.js
const getDocumentOnClick = async () => {
try {
var {data} = await pullMyPDF()
var blob = new Blob([data], { type: "application/pdf" });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "myFileName.pdf";
link.click();
} catch (e) {
console.log(e)
}
}
Here
var {data} = await pullMyPDF()
is returning the following content. I compared it with the result returned by the Postman, and it is the same. The generated file size is not empty from the react too. I am not able to find out where is it wrong
Below is the response from API endpoint for the fetchFile
I had a similar problem and I fixed it with this:
spa
axios.post(
'api-url',
formData,
{
responseType: 'blob',
headers: {
'Accept': 'application/pdf'
}
})
.then( response => {
const url = URL.createObjectURL(response.data);
this.setState({
filePath: url,
fileType: 'pdf',
})
})
.catch(function (error) {
console.log(error);
});
api
[HttpPost]
public async Task<IActionResult> Post()
{
var request = HttpContext.Request;
var pdfByteArray = await convertToPdfService.ConvertWordStreamToPdfByteArray(request.Form.Files[0], "application/msword");
return File(pdfByteArray, "application/pdf");
}
When the response type is a blob and accepted 'application / pdf' in the header, with that config the job is done ;) ...
Something that worked for me was to send the bytes as base64 from the controller.
API:
public async Task<ActionResult> GetAsync() {
var documentBytes = await GetDocumentAsync().ConfigureAwait(false);
return Ok(Convert.ToBase64String(documentBytes))
}
Front End:
client.get(url, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(response => {
const link = document.createElement('a');
link.href = "data:application/octet-stream;base64," + response.data;
link.download = 'file.pdf';
link.click();
})
.catch(error => {
console.log(error);
})
I hope this solves your problem.
UPDATED with res.send(data) instead of res.json(data)
Using Angular 6 and NodeJS I am doing a web application.
I am trying to download a file from a http post request.
I send a request to the server like this. From my component I call a function in a service. In the component, I susbscribe to have the answer of the server and when I have it I create a new Blob with the response and I Use FileSaver to download the pdf.
Now, when I received the answer from the server, the client sees it like an error whereas the status is 200. The error message is:
"Http failure during parsing for http://localhost:3000/api/experiment/regression"
See the screenshot below.
Component.ts
this.api.postML(this.regression).subscribe(
res => {
console.log(res);
let pdf = new Blob(res.data, { type: "application/pdf" });
let filename = "test.pdf";
FileSaver.saveAs(pdf, filename);
},
err => {
alert("Error to perform the regression");
console.log(err);
}
);
API.Service.ts
public postML(data): Observable<any> {
// Create url
let url = `${baseUrl}${"experiment/regression"}`;
let options = {
headers: { "Content-Type": "application/json", Accept: "application/pdf" }
};
// Call the http POST
return this.http
.post(url, data, options)
.pipe(catchError(this.handleError));
}
Then from the server, it executes some code with the data sent and generates a PDF file.
Then, I would like to send the pdf as a response to the client.
I tried like this:
fs.readFile("/home/user/test.pdf", function(err, data) {
let pdfName = "Report.pdf";
res.contentType("application/pdf");
res.set("Content-Disposition", pdfName);
res.set("Content-Transfer-Encoding", "binary");
console.log(data);
console.log("Send data");
res.status(200);
res.send(data);
});
In the client, I have the answer. The console log is:
Finally, I found a video tutorial and it was very basic.
Node.js Server:
const express = require("express");
const router = express.Router();
router.post("/experiment/resultML/downloadReport",downloadReport);
const downloadReport = function(req, res) {
res.sendFile(req.body.filename);
};
Angular Component:
import { saveAs } from "file-saver";
...
download() {
let filename = "/Path/to/your/report.pdf";
this.api.downloadReport(filename).subscribe(
data => {
saveAs(data, filename);
},
err => {
alert("Problem while downloading the file.");
console.error(err);
}
);
}
Angular Service:
public downloadReport(file): Observable<any> {
// Create url
let url = `${baseUrl}${"/experiment/resultML/downloadReport"}`;
var body = { filename: file };
return this.http.post(url, body, {
responseType: "blob",
headers: new HttpHeaders().append("Content-Type", "application/json")
});
}
I'm trying to return a JSON result to my client using IHttpActionResult.
My .Net code, looks like this:
[AllowAnonymous, HttpPost, Route("")]
public IHttpActionResult Login(LoginRequest login)
{
if (login == null)
return BadRequest("No Data Provided");
var loginResponse = CheckUser(login.Username, login.Password);
if(loginResponse != null)
{
return Ok(new
{
message = "Login Success",
token = JwtManager.GenerateToken(login.Username, loginResponse.Roles),
success = true
});
}
return Ok( new
{
message = "Invalid Username/Password",
success = false
});
}
This doesn't work though, as I never seem to see the JSON on the response after my JavaScript fetch:
const fetchData = ( {method="GET", URL, data={}} ) => {
console.log("Calling FetchData with URL " + URL);
var header = {
'Content-Type': "application/json",
}
// If we have a bearer token, add it to the header.
if(typeof window.sessionStorage.accessToken != 'undefined')
{
header['Authorization'] = 'Bearer ' + window.sessionStorage.accessToken
}
var config = {
method: method,
headers: header
};
// I think this adds the data payload to the body, unless it's a get. Not sure what happens with a get.
if(method !== "GET") {
config = Object.assign({}, config, {body: JSON.stringify(data)});
}
// Use the browser api, fetch, to make the call.
return fetch(URL, config)
.then(response => {
console.log(response.body);
return response;
})
.catch(function (e) {
console.log("An error has occured while calling the API. " + e);
});
}
There is no JSON available in the body.
How do I get aresult back to my client to parse? response.body doesn't have the json object.
The console.log shows:
While the request/response shows:
Using striped's advice: console.log(response.json())
I see the message there. It seems to be in the wrong place. Shouldn't it be in the body?
Fetch works like this
Body methods
Each of the methods to access the response body returns a Promise that
will be resolved when the associated data type is ready.
text() - yields the response text as String
json() - yields the result of JSON.parse(responseText)
blob() - yields a Blob
arrayBuffer() - yields an ArrayBuffer
formData() - yields FormData that can be forwarded to another request
I think you need to
return fetch(URL, config)
.then(response => response.json())
.catch(e => console.log("An error has occured while calling the API. " + e));
doc here: https://github.github.io/fetch/
Your are making a GET request but your controller method is expecting a POST request.
I have a Node JS Rest get service which send the zip folder created on my server in binary encoded format. But unable to download this on client. I am unable to open the zip.
Server controller
botsController.exportBot = (req,res) =>{
let botId = req.params.botId;
zipFolder("...pathtoZip/", "pathToFolder/my.zip", function(err) {
if(err) {
res.statusCode = 500;
return res.send({
success: false,
message: "Something went wrong while fetching the bot data",
err_details: err
});
} else {
let filetext;
let zipFolder= "pathToFolder/my.zip";
if (fs.existsSync(zipFolder)) {
filetext = fs.readFileSync(zipFolder, "utf-8");//tried encoding binary
}
var headers = {
'Content-Type': 'application/octet-stream',//tried application/zip
'Content-Disposition': "attachment; filename=" + botId + '.zip'
};
res.writeHead(200, headers);
return res.end(filetext,"binary");
}
});
And on angular js Service I have fetch the data. And on component I have downloaded it.But download zip is corrupted it gives error unable to open the zip.
Angular 2 Service
exportBot() {
let token = localStorage.token;
let headerObj = {
'Authorization': token,
responseType: ResponseContentType.ArrayBuffer
};
let headers = new Headers(headerObj);
return this.http.get("export/botId", { headers: headers })
.map((res) => new Blob([res['_body']], { type: 'application/zip' }))
.catch(this.errorHandler);
}
And on component end
exportBot() {
this.loader = false;
this.botdataservice.exportBot()
.subscribe(res => {
console.log(`excel data: ${res}`);
window.open(window.URL.createObjectURL(res));
},
err => {
console.log(err);
})
}
In your package.json add the dependency :
"file-saver": "^1.3.3",
And you can use the file saver on your get request as below :
public getBlob(url: string): Observable<Blob> {
this.showLoader();
return this.http.get(url, {responseType: 'blob'})
.catch(this.onCatch)
.do(res => {
this.onSuccess(res);
}, (error: any) => {
this.onError(error);
})
.finally(() => {
this.onEnd();
});
}
and the method to download :
downloadFile(fileid: string) {
return this._http.getBlob(this._http.backendURL.downloadFile.replace(':fileid', fileid))
}
And the you call the Filesaver when subscribing data as this :
downloadFile() {
this._downloadFileService.downloadFile(this.model.fileid)
.subscribe(
data => {
FileSaver.saveAs(data, this.form.getRawValue().title);
}
);
}
I hope this can help.
You can convert your file to base64 by using btoa(unescape(encodeURIComponent(binarydata))) or in case of array buffer try btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
Either can even send base64 file from your node server
filetext = fs.readFileSync(zipFolder);
return res.end(new Buffer(filetext ).toString('base64'));
in that case change your headers
and use following code to download it
var base64Str = "UEsDBAoAAgAAAMWqM0z4bm0cBQAAAAUAAAAJAAAAdmlub2QudHh0dmlub2RQSwECFAAKAAIAAADFqjNM+G5tHAUAAAAFAAAACQAkAAAAAAABACAAAAAAAAAAdmlub2QudHh0CgAgAAAAAAABABgAUCMddj2R0wFA/Bx2PZHTAWCGE3Y9kdMBUEsFBgAAAAABAAEAWwAAACwAAAAAAA==";
var elem = window.document.createElement('a');
elem.href = "data:application/zip;base64,"+base64Str
elem.download = "my.zip";
document.body.appendChild(elem);
elem.click();
document.body.removeChild(elem);