Download PDF in angular generated from Spring Boot Server - javascript

I am working to download a pdf file from User Interface (Angular), generated from Spring boot .
I am able to download pdf file from browser with same API.
Quick help will be much appreciated.
In postman it gives response like this -
When trying from UI then getting below error-
SyntaxError: Unexpected token % in JSON at position 0 at JSON.parse () at XMLHttpRequest.onLoad
message: "Unexpected token % in JSON at position 0"
stack: "SyntaxError: Unexpected token % in JSON at position 0↵ at JSON.parse ()↵ at XMLHttpRequest.onLoad (http://localhost:4200/vendor.js:19662:51)↵
API Code
Controller code-
#RequestMapping(value = "/downloadPDF/", method = RequestMethod.GET, produces = "application/pdf")
public ResponseEntity<Resource> downloadServicePack(#RequestHeader("Authorization") String token,
HttpServletRequest request) throws WorkflowException, Exception {
String fileName = "TWEVL_ServiceDesignPack.pdf";
// String fileName ="ServiceDesignPdf.pdf";
Resource resource = fileStorageService.loadFileAsResource(fileName);
// Try to determine file's content type
String contentType = null;
try {
contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
} catch (IOException ex) {
// logger.info("Could not determine file type.");
}
// Fallback to the default content type if type could not be determined
if (contentType == null) {
contentType = "application/octet-stream";
}
return ResponseEntity.ok().contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
Service Code-
#Service
public class FileStorageService {
private final Path fileStorageLocation;
#Autowired
public FileStorageService(FileStorageProperties fileStorageProperties) throws Exception {
this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
.toAbsolutePath().normalize();
try {
Files.createDirectories(this.fileStorageLocation);
} catch (Exception ex) {
throw new Exception("Could not create the directory where the uploaded files will be stored.", ex);
}
}
public Resource loadFileAsResource(String fileName) throws Exception {
try {
Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
Resource resource = new UrlResource(filePath.toUri());
if(resource.exists()) {
return resource;
} else {
throw new Exception("File not found " + fileName);
}
} catch (Exception ex) {
throw new Exception("File not found " + fileName, ex);
}
}
}
Angular Code-
JWT Interceptor to pass token & other header-
#Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
// add authorization header with jwt token if available
const token = this.authenticationService.currentUserValue;
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token.token}`,
Accept: `application/pdf`,
responseType:'blob',
'Content-Type':`application/pdf`
}
});
return next.handle(request);
}
}
API Call
downloadServicePackPDF() {
this.tcmtSrv
.downloadServicePack()
.subscribe(
(blob: Blob) => {
console.log('report is downloaded');
},
(error) => {
console.log(error);
}
);
}
Service Code -
downloadServicePack() {
//header is being passed from interceptor
return this.apiSrv.get(DOWNLOAD_SERVICE_PACK,'');
}
Request Header-

I was not passing responseType in the interceptor. I tried to pass it service ts but Interceptor was overriding these headers & other params given at service level.
Passed header like below in interceptor & it worked -
const newRequest = request.clone({ setHeaders: { Authorization: Bearer ${token.token}, "Content-Type": "text/plain", Accept: "text/plain" },responseType: "text", });

Related

Receive formatted 'multipart/form-data' response in Angular 7.x

I am developing an Angular application that shows some images to the user.
I would like to obtain those images from a single REST call to a web service: given the fact i am already uploading the images via a FormData object, i would like to receive those images in the same way (so, basically, via content-type: multipart/form-data).
At the moment, using the following code:
this.http.post('api/load', {}, {headers: {'Accept': 'multipart/form-data'},
responseType:'text', observe: 'response'});
i am actually receiving the full body of the response in a text format, like this:
--974b5730-ab25-4554-8a69-444664cab379
Content-Disposition: form-data; name=result
{"bar":[1,2,3,4], "foo": true}
--974b5730-ab25-4554-8a69-444664cab379
Content-Disposition: form-data; name=image; filename=image1.jpg; filename*=utf-8''image1.jpg
--- binarycontent...
But it's in a raw, text format.
How can i receive a multipart/form-data response formatted by its boundaries, or a in clean way in Angular 7.x?
One of the solution is to implement an interceptor service where you can format multipart/form-data response.
For example, your inteceptor will be - multipart.interceptor.ts :
#Injectable()
export class MultipartInterceptService implements HttpInterceptor {
private parseResponse(response: HttpResponse<any>): HttpResponse<any> {
const headerValue = response.headers.get('Content-Type');
const body = response.body;
const contentTypeArray = headerValue ? headerValue.split(';') : [];
const contentType = contentTypeArray[0];
switch (contentType) {
case 'multipart/form-data':
if (!body) {
return response.clone({ body: {} });
}
const boundary = body?.split('--')[1].split('\r')[0];
const parsed = this.parseData(body, boundary); // function which parse your data depends on its content (image, svg, pdf, json)
if (parsed === false) {
throw Error('Unable to parse multipart response');
}
return response.clone({ body: parsed });
default:
return response;
}
}
// intercept request and add parse custom response
public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(customRequest).pipe(
map((response: HttpResponse<any>) => {
if (response instanceof HttpResponse) {
return this.parseResponse(response);
}
})
);
}
}

Angular can't get response status text

export class GitComponent implements OnInit {
http: HttpClient;
headerForAjax: HttpHeaders;
constructor(http: HttpClient) {
this.http = http;
}
ngOnInit(): void {
const headers = 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJzYXNobyIsImF1dGgiOiJST0xFX1VTRVIiLCJleHAiOjE1MjQwODcyMzJ9.MUv5RgI9LxQyrrCfjfX8HR2-XiQmz4vjLqH7V_0Du7VFLC0WrK_y3FfeNoT2Nj_uguIK2ss7jv-LNiHuCGtz4A';
this.headerForAjax = new HttpHeaders().set('Authorization', headers);
const linkBindingModel = {
title: 'angular2',
linkUrl: 'angularUr2l',
imageUrl: 'imageUrl22'
};
this.http.post('http://localhost:8080/links/add', linkBindingModel, {headers: this.headerForAjax}).subscribe((e) => {
console.log(e);
});
}
}
So this ajax is send to my spring server and the server saves the data correctly in the DB, it basically all works well.
But i can't get the response status, i mean how can i get the 200 response status number or text that my server sends back?
try this, you can pass in an object with observe key to get the complete response
this.http.post('http://localhost:8080/links/add', linkBindingModel, {headers:
this.headerForAjax, observe: 'response'}).subscribe((response) => {
console.log(response.status); // response status
console.log(response.body); // response body (returned response)
});

Mutipart File upload using Angularjs and Spring

I'm trying to upload files using Angularjs for REST API exposed via Spring :
This is my Controller:
#RequestMapping(value = util/images/{partyId},
method = RequestMethod.POST)
public JsonNode uploadPartyRefImage(#RequestPart("file") MultipartFile inputFile,
#PathVariable String partyId){
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jNode = null;
try {
String[] fileInput = ((DiskFileItem) ((CommonsMultipartFile) inputFile).getFileItem()).getName().split("\\.");
Path storagePath= Paths.get(uploadPath);
FileSystemUtil.writeFile(storagePath,inputFile.getInputStream());
jNode = objectMapper.readTree("{\"type\":\"" + "success" + "\",\"fileStorePath\":\"" + pathString + "\"}");
} catch (Exception exApi) {
LOGGER.error("Error uploading Party attached Image "+ exApi);
}
return jNode;
}
This API works fine when used via Postman. The Postman call:
But when calling through angular it throws Exception:
Angular service:
function uploadImage(formData,partyRefId){
console.log(utilService);
if (utilService) {
return utilService.request({
method: "POST",
resource: "/images/" + partyRefId,
headers: { 'Content-Type': undefined},
processData: false,
transformRequest: angular.identity,
mimeType: "multipart/form-data",
cache: false,
data: formData
})
.then(function (data) {
if (data) {
return getResultDataFromResponse(data);
}
}, function (error) {
console.log('error invoking document upload service', error);
});
}
}
Angular Controller:
$ctrl.uploadDocument = function () {
var formData = new FormData();
formData.append("file", k.documentfile.lfFile);
var fileName = "PARTY01" + k.documentReference;
fbeOnboardingWizardService.uploadImage(formData,fileName)
.then(function (data) {
if(data.type == "success")
console.log(data.fileStorePath);
},function (error) {
console.log(error);
});
};
Error in Jboss:
02:06:25,442 WARN [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver] (http--0.0.0.0-8080-4) Handler execution resulted in exception: Content type 'null' not supported
If I update the Content-Type to "multipart/form-data" in angular service
Error in Jboss:
Servlet.service() for servlet appServlet threw exception: org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found

Angular 2 Refresh access token on 401 error and repeat initial request

TLDR: My task is to complete 3 requests instead of 1 and return the last response as a response to the first request without any additional modifications of the request initiator.
I have extended the Angular Http class to automatically append authorization headers to all of my requests and implement my own authorization error handling.
It looks like this:
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
// ... append some headers
super.request(url, options).catch((error: Response) => {
if (error.status === 401 || error.status === 403 ) {
// todo: Send refreshToken request to get new credentials
// todo: Send current request again with new credentials
// todo: If request is completed properly pretend everything was fine and return response
}
});
}
I want to catch authorization errors, fix them by sending token refresh request and return proper response to the initial request.
There's a lot of code using http now and I don't want to change it so the fixed response has to be returned as the initial would have been without anybody knowing about it.
One of the approaches was to use synchronous requests but it's not a good idea I think.
Could you tell please if the solution is possible and how can I achieve it?
PS. There may be a problem when another request is executed while the token is being refreshed and crash into an authorization causing one more token refresh. But this is not that important now.
The aim was achieved mostly by using flatMap to compose requests.
Key functions:
Check if request request returns 401
If 401: tries to fix renew necessary tokens and sends request again
The subscriber knows nothing about error if it's fixed
It's designed to work with the REST authentication model which includes:
guest token - for unauthorized users (gToken)
auth token - for authorized users - (aToken)
refresh token - to refresh expired aToken (refresh_token)
Most likely you will need to rewrite requests to fit your backend but here's a well-commented Services to be provided instead of default Http:
import {Injectable} from '#angular/core';
import {
Http, XHRBackend, RequestOptions, RequestOptionsArgs, Request, Response, RequestMethod,
Headers
} from "#angular/http";
import { Observable } from "rxjs";
import { StorageService } from "../storage.service";
import { AppService } from "./app.service";
#Injectable()
export class HttpClientService extends Http {
private autoAppendHeadersDefault = true;
constructor(
backend: XHRBackend,
defaultOptions: RequestOptions,
private storageService: StorageService,
private appState: AppService,
) {
super(backend, defaultOptions);
this.autoAppendHeadersDefault = this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS;
}
request(url: string | Request, options?: RequestOptionsArgs, disableTryFix = false): Observable<Response> {
// Checking if the request needs headers to be appended
let assetRequest = false;
if(url instanceof Request) {
if(url.url.startsWith("/assets")) {
assetRequest = true;
}
}
// Appending headers
if(!assetRequest && this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS && url instanceof Request) {
// append aToken || gToken
let token = this.storageService.get('aToken');
if('undefined' === typeof token || !token) {
token = this.storageService.get('gToken');
}
if('undefined' !== typeof token && token) {
url.headers.set('Authorization', `Bearer ${token}`);
} else {
// neither aToken nor gToken are set
if(disableTryFix) {
this.removeAllTokens();
return Observable.throw({error: "Can't reauth: 01"});
}
return this.tryFixAuth().flatMap(
(res:any) => {
res = res.json();
this.storageService.set('gToken', res.access_token);
return this.request(url, options, true);
}
);
}
// headers appended to every request
if(!url.headers.get('Content-Type')) {
url.headers.append('Content-Type', 'application/json');
}
}
this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS = this.autoAppendHeadersDefault;
return super.request(url, options).catch((error: Response) => {
if (error.status === 401 /* || error.status === 403 */ ) {
if(disableTryFix) {
this.removeAllTokens();
this.navigateOnAuthFail();
return Observable.throw({error: "Can't reauth: 02"});
}
return this.tryFixAuth().flatMap(
(res: any) => {
res = res.json();
if('undefined' !== typeof res.refresh_token)
{
// got aToken & refresh_token
this.storageService.set('aToken', res.access_token);
this.storageService.set('refresh_token', res.refresh_token);
}
else if('undefined' !== typeof res.access_token)
{
// got only gToken
this.storageService.set('gToken', res.access_token);
}
else
{
console.log('tryFix: nothing useful returned')
// got no aToken, no gToken, no refresh_token
}
// retry request
return this.request(url, options, true);
}
);
}
// handle invalid refresh_token
if(disableTryFix && error.status === 400) {
console.log('Wrong refresh token (400)');
this.storageService.remove('refresh_token');
this.storageService.remove('aToken');
this.navigateOnAuthFail();
// handle invalid refresh token
}
return Observable.throw(error);
});
}
private tryFixAuth(): Observable<Response> {
console.log('Trying to fix auth');
if(this.storageService.get('refresh_token'))
{
return this.refreshToken();
}
else if(this.storageService.get('aToken'))
{
// no refresh_token, but aToken
// since aToken is dead it's not useful
this.storageService.remove('aToken');
}
else
{
// no aToken, no refresh_token
// possibly there's a gToken
// since the request is trying to fix itself (is failed) the gToken is most likely not valid
return this.guestToken();
}
}
// sends request with refresh_token to get new aToken
// the request returns only aToken and refresh_token, no gToken
private refreshToken(): Observable<Response> {
// is called only when refresh_token is set
let refreshToken = this.storageService.get('refresh_token');
// check refresh_token in case it's not checked before
if('undefined' === typeof refreshToken || !refreshToken || refreshToken == 'undefined') {
this.storageService.remove('refresh_token');
// there's no refresh_token saved
return Observable.throw({error: "Refresh token is not set"});
}
// form refresh_token request
const headers = new Headers();
headers.append('Authorization', `Bearer ${this.storageService.get('gToken')}`);
headers.append('Content-Type', 'application/json');
const url = `${this.appState.config.WEBSITE_ENDPOINT}/oauth/v2/token`;
const localData = JSON.stringify({
"client_id": this.appState.config.CLIENT_ID,
"client_secret": this.appState.config.CLIENT_SECRET,
"grant_type": 'refresh_token',
"refresh_token": refreshToken
});
this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS = false;
// refresh_token request
return this.request(
new Request({
method: RequestMethod.Post,
url: url,
headers: headers,
body: localData
}),
null, true);
}
// sends request to get new gToken
private guestToken(): Observable<Response> {
const url = `${
this.appState.config.WEBSITE_ENDPOINT}/oauth/v2/token?client_id=${
this.appState.config.CLIENT_ID}&client_secret=${
this.appState.config.CLIENT_SECRET}&grant_type=client_credentials`;
this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS = false;
return super.get(url);
}
// Aux methods
private navigateOnAuthFail() {
console.warn('Page is going to be refreshed');
// redirect to auth is performed after reload by authGuard
// it's possible to add some warning before reload
window.location.reload();
}
private removeAllTokens() {
this.storageService.remove('aToken');
this.storageService.remove('gToken');
this.storageService.remove('refresh_token');
}
}

is possible post data from android to node js?

i use node.js as server and android as client, the server work normally send and receive data from client (except android)
here my code in javascript
function put(id, data, callback) {
$.ajax('http://mydomain.com:8888/' + id + '/', {
type: 'POST',
data: JSON.stringify(data),
dataType: 'json',
success: function(data) {
if (callback)
callback(data);
},
error: function() {
if (callback)
callback(false);
}
});
}
and my node script
function handler ( req, res ) {
if ( req.method === 'POST' ) {
console.log('receive data from post');
}
}
the code above has successfully sent data.
i want to send data (post) to node (like what javascript does) in android?
how i achieve that?
thanks
But of course
Here you go
public void postData() {
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.yoursite.com/script.php");
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("id", "12345"));
nameValuePairs.add(new BasicNameValuePair("stringdata", "AndDev is Cool!"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
}

Categories