export to excel from a byte [] in angular - excel

I have the response json from the backend (spring boot):
private byte[] archivoExcel;
private String extension;
private String mime;
What I need in angular is to get this byte [] and export it to excel, for this my answer json in angular is:
export class RespuestaExportar {
archivoExcel: ArrayBuffer;
extension: string;
mime: string;
}
and in my component.ts file I have:
this.reversionesService.getReversionesExportarSeguimiento(this.solicitud).subscribe(res => { this.respuestaExportar=res; let file = new Blob([this.respuestaExportar.archivoExcel], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
var fileURL = URL.createObjectURL(file); window.open(fileURL); }
When I run the 'export' button, it consumes correctly, and it downloads the excel, but this file is damaged. Do I need one more step to solve it? or there is another alternative, since I need to get this byte [] from the backEnd.

I think you can guide yourself from this service that I perform for my backend (SpringBoot) I send a responseObject as json
ObjectResponse response = new ObjectResponse();
ByteArrayInputStream in = getExcel();
byte[] array = new byte[in.available()];
in.read(array);
httpStatus = HttpStatus.OK;
response.setResultado(array);
return new ResponseEntity<>(response, httpStatus);
and I get a Json response with the structure that sent the data is that when serializing it, the response.getResult arrives in base64, that is, already transformed to the client that receives it.
So in my frontend (Angular) I proceed to transform it into a Blob and be able to work the file.
this.subcriber = this.reporteService.generarExcel (). subscribe ((b64Data: any) => {
const byteCharacters = atob (b64Data.result);
const byteNumbers = new Array (byteCharacters.length);
for (let i = 0; i <byteCharacters.length; i ++) {
byteNumbers [i] = byteCharacters.charCodeAt (i);
}
const byteArray = new Uint8Array (byteNumbers);
let blob = new Blob ([byteArray], {type: 'application / vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
const url = window.URL.createObjectURL (blob);
const anchor = document.createElement ('a');
anchor.download = `file.xlsx`;
anchor.href = url;
anchor.click ();
messageService = {
state: false,
messages: null
};
}, (err) => {
this.subcriber.unsubscribe ();
})
I hope it helps you

Related

How to transfer image from server to client with node http header size restrictions

Transferring image (base64 encoded, created with Mapguide server) to client. I am able to output the image to the console and test it is correct. Using Node with npm and Vite for develpment web server. When I try to set imgLegend.src = data; I get this error "431 (Request Header Fields Too Large)" I believe it is the Node default max-http-header-size causing the problem. Have attempted to set --max-http-header-size=80000 with no luck. I am starting my dev server in package.json file like this: "start": "vite --host 0.0.0.0",
Does anyone know of a way around this or a better way to transfer the image from server to client?
here is the relevant code.
Client side:
//add legend
const mapVpHeight = document.getElementById('map').clientHeight;
var url = mgServer + "/Cid_Map/LayerManager.aspx/GetLegendImage";
var values = JSON.stringify({ sessionId: sessionId, mgMapName: mapName, mapVpHeight: mapVpHeight });
var imgLegend = new Image();
//console.log(values);
$.ajax({
url: url,
type: "POST",
contentType: "application/json; charset=utf-8",
data: values,
dataType: 'html',
success: function (data) {
console.log(data); //
imgLegend.src = data; //node.js won't allow http header as large as this image, about 18kb
},
error: function (xhr, textStatus, error) {
console.log(textStatus);
}
});
Server Side:
[WebMethod]
public static string GetLegendImage(string sessionId, string mgMapName, int mapVpHeight)
{
string tempDir = System.Configuration.ConfigurationManager.AppSettings["tempDir"];
string legFilePath = tempDir + sessionId + "Legend.png";
string configPath = #"C:\Program Files\OSGeo\MapGuide\Web\www\webconfig.ini";
MapGuideApi.MgInitializeWebTier(configPath);
MgUserInformation userInfo = new MgUserInformation(sessionId);
MgSiteConnection siteConnection = new MgSiteConnection();
siteConnection.Open(userInfo);
MgMap map = new MgMap(siteConnection);
MgResourceService resourceService = (MgResourceService)siteConnection.CreateService(MgServiceType.ResourceService);
map.Open(resourceService, mgMapName);
MgColor color = new MgColor(226, 226, 226);
MgRenderingService renderingService = (MgRenderingService)siteConnection.CreateService(MgServiceType.RenderingService);
MgByteReader byteReader = renderingService.RenderMapLegend(map, 200, mapVpHeight, color, "PNG");
MgByteSink byteSink = new MgByteSink(byteReader);
byteSink.ToFile(legFilePath);
//try this
//byte[] buffer = new byte[byteReader.GetLength()]; //something doesn't work here byteReader doesn't give comeplete image
//byteReader.Read(buffer, buffer.Length);
//loading image file just created, converting to base64 image gives correct image
string legendImageURL = "";
using (Stream fs = File.OpenRead(legFilePath))
{
BinaryReader br = new System.IO.BinaryReader(fs);
byte[] bytes = br.ReadBytes((int)fs.Length);
string strLegendImage = Convert.ToBase64String(bytes, 0, bytes.Length);
legendImageURL = "data:image/png;base64," + strLegendImage;
}
byteReader.Dispose();
byteSink.Dispose();
return legendImageURL;
//return buffer;
}
The 431 status code complains about the header length of your request ..
trace the request in your browsers dev tool network tab and study the header fields in your request in some special cases if your cookies get set to often with unique key value pairs this could be the problem...
May be you can copy and share the request response from your browsers network tab to provide some detailed information... especially the request response of the endpoint and look up the cookie/session storage maybe you find some suspicious stuff.
Good look :)

ComputerVisionClient or Xamarin Essentials Error - Invalid URI: The format of the URI could not be determined when calling method ReadInStreamAsync

So I am capturing a photo and opening a stream using Xamarin.Essentials 1.7 MediaPicker built into Essentials.
When I call the ReadInStreamAsync(stream) method in Computer Vision Client, I get an error and my Xamarin.Forms app breaks inside the method: 'Invalid URI: The format of the URI could not be determined.'
This is the stream.Name value - '/data/user/0/com.companyname.xamphotoappdemo2/cache/2203693cc04e0be7f4f024d5f9499e13/198fd32db9cc4be38a493325974fa138/d964251252fc4963aca94339d73a8007.jpg'
This is my code:
var file = await MediaPicker.CapturePhotoAsync(new MediaPickerOptions
{ Title = "Please take a photo" });
if(file != null)
{
var stream = await file.OpenReadAsync();
chosenImage.Source = ImageSource.FromStream(() => stream);
// 2. Add OCR logic.
var client = Authenticate(ApiSettings.subscriptionKey, ApiSettings.endpoint);
var text = await client.ReadInStreamAsync(stream);
//after the request, get the operation location
string operationLocation = text.OperationLocation;
//we only need the operation ID, not the whole URL
const int numberOfCharsInOperationId = 36;
string operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
//Get the ocr read results
ReadOperationResult results;
do
{
results = await client.GetReadResultAsync(Guid.Parse(operationId));
}
while ((results.Status == OperationStatusCodes.Running || results.Status == OperationStatusCodes.NotStarted));
var readResults = results.AnalyzeResult.ReadResults;
var expirationDates = from page in readResults
from line in page.Lines
where line.Text.Contains("EXPIRES") && line.Words.Count == 4
select line.Words[3].Text;
expirationDate.Text = expirationDates.ToString();
photoPath.Text = file.FullPath;
The image is displaying as expected in the XAML Image control and that is reading the image source from the stream, so is this a bug in the ReadInStreamAsync method?

Could not parse the ephemeral key response following protocol

I am trying to create an ephemeral key in my IOS app. I can successfully create a stripe customer that saves in my firebase console and on my stripe dashboard. However, when I try to create the ephemeral key, I am receiving the error in my ios console after trying to view the checkout controller.
'Could not parse the ephemeral key response following protocol STPCustomerEphemeralKeyProvider. Make sure your backend is sending the unmodified JSON of the ephemeral key to your app.
and on my firebase function logs I am seeing,
createEphemeralKey
Request has incorrect Content-Type.
createEphemeralKey
Invalid request, unable to process.
in my index.js file, the code that I am using is
exports.createEphemeralKey = functions.https.onCall(async(data, context) => {
var stripeVersion = data.api_version;
const customerId = data.customer_id;
return stripe.ephemeralKeys.create(
{customer: customerId},
{stripe_version: stripeVersion}
).then((key) => {
return key
}).catch((err) => {
console.log(err)
})
})
Below is how I create my stripe customer.
exports.createStripeCustomer = functions.auth.user().onCreate((user) => {
return stripe.customers.create({
email: user.email,
}).then((customer) => {
return admin.database().ref(`/stripe_customers/${user.uid}/customer_id`).set(customer.id);
});
});
and then myAPIClient looks like.
enum APIError: Error {
case unknown
var localizedDescription: String {
switch self {
case .unknown:
return "Unknown error"
}
}
}
static let sharedClient = MyAPIClient()
var baseURLString: String? = "https://myProject.cloudfunctions.net/"
var baseURL: URL {
if let urlString = self.baseURLString, let url = URL(string: urlString) {
return url
} else {
fatalError()
}
}
func createCustomerKey(withAPIVersion apiVersion: String, completion: #escaping STPJSONResponseCompletionBlock) {
let url = self.baseURL.appendingPathComponent("ephemeral_keys")
Alamofire.request(url, method: .post, parameters: [
"api_version": apiVersion,
])
.validate(statusCode: 200..<300)
.responseJSON { responseJSON in
switch responseJSON.result {
case .success(let json):
completion(json as? [String: AnyObject], nil)
case .failure(let error):
completion(nil, error)
}
}
}
On my checkOutVC, I have
var stripePublishableKey = "pk_test_testProjectKey"
var backendBaseURL: String? = "https://myProject.cloudfunctions.net"
let customerContext = STPCustomerContext(keyProvider: MyAPIClient())
init(price: Int, settings: Settings) {
if let stripePublishableKey = UserDefaults.standard.string(forKey: "StripePublishableKey") {
self.stripePublishableKey = stripePublishableKey
}
if let backendBaseURL = UserDefaults.standard.string(forKey: "StripeBackendBaseURL") {
self.backendBaseURL = backendBaseURL
}
let stripePublishableKey = self.stripePublishableKey
let backendBaseURL = self.backendBaseURL
assert(stripePublishableKey.hasPrefix("pk_"), "You must set your Stripe publishable key at the top of acceptWorker.swift to run this app.")
assert(backendBaseURL != nil, "You must set your backend base url at the top of acceptWorker.swift to run this app.")
Stripe.setDefaultPublishableKey(self.stripePublishableKey)
let config = STPPaymentConfiguration.shared()
config.appleMerchantIdentifier = self.appleMerchantID
config.companyName = self.companyName
config.requiredBillingAddressFields = settings.requiredBillingAddressFields
config.requiredShippingAddressFields = settings.requiredShippingAddressFields
config.shippingType = settings.shippingType
config.additionalPaymentOptions = settings.additionalPaymentOptions
config.cardScanningEnabled = true
self.country = settings.country
self.paymentCurrency = settings.currency
self.theme = settings.theme
MyAPIClient.sharedClient.baseURLString = self.backendBaseURL
let paymentContext = STPPaymentContext(customerContext: customerContext, configuration: config, theme: settings.theme)
self.paymentContext = STPPaymentContext(customerContext: customerContext)
super.init(nibName: nil, bundle: nil)
self.paymentContext.delegate = self
self.paymentContext.hostViewController = self
self.paymentContext.paymentAmount = 5000 // This is in cents, i.e. $50 USD
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
I apologize for the long lines of code but I am really running into a brick wall. Why isnt the backend creating the ephemeralKey for customers?
Two things are jumping out at me:
You’ve written a callable type function (using onCall) but you’re
trying to call it with a normal HTTP request. These functions need to
be called with Firebase’s client library
(https://firebase.google.com/docs/functions/callable#call_the_function).
This stack overflow answer provides some great links about this:
Firebase Cloud Function to delete user.
Your firebase function is parsing stripe_version and customer_id from
data, but your request is only sending api_version. Where in your
code are you sending stripe_version and customer_id?

uploaded files to Azure are corrupted when using dio

I'm trying to upload a file from my phone to azure blob storage as a BlockBlob with a SAS. I can get the file to upload, but it can't be opened once downloaded. The file gets corrupted somehow. I thought this was a content-type problem, but I have tried several different approaches to changing to content-type. Nothing has worked so far.
My code:
FileInfo _fileInfo = await filePicker(); // get the file path and file name
// my getUploadInfo fires a call to my backend to get a SAS.
// I know for a fact that this works because my website uses this SAS to upload files perfectly fine
UploadInfo uploadInfo = await getUploadInfo(_fileInfo.fileName, _fileInfo.filePath);
final bytes = File(_fileInfo.filePath).readAsBytesSync();
try {
final response = await myDio.put(
uploadInfo.url,
data: bytes,
onSendProgress:
(int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
options:
dioPrefix.Options(headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': mime(_fileInfo.filePath),
})
);
} catch (e) {
print(e);
}
This code uploads a file just fine. But I can't open the file since it becomes corrupted. At first, I thought this was a Content-Type problem, so I've tried changing the content type header to: application/octet-stream and multipart/form-data as well. That doesn't work.
I've also tried to do
dioPrefix.FormData formData =
new dioPrefix.FormData.fromMap({
'file': await MultipartFile.fromFile(
_fileInfo.filePath,
filename: _fileInfo.fileName,
)
});
...
final response = await myDio.put(
uploadInfo.url,
data: formData, // This approach is recommended on the dio documentation
onSendProgress:
...
but this also corrupts the file. It gets uploaded, but I can't open it.
I have been able to successfully upload a file with this code, but with this approach I cannot get any type of response so I have no idea whether it uploaded successfully or not (Also, I can't get the progress of the upload):
try {
final data = imageFile.readAsBytesSync();
final response = await http.put( // here, response is empty no matter what i try to print
url,
body: data,
headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': mime(filePath),
});
...
Any help would be greatly appreciated. Thanks
I tried to upload a file using dio in Dart to Azure Blob Storage, and then download and print the content of the file, as the code below.
import 'package:dio/dio.dart';
import 'dart:io';
main() async {
var accountName = '<account name>';
var containerName = '<container name>';
var blobName = '<blob name>';
var sasTokenContainerLevel = '<container level sas token copied from Azure Storage Explorer, such as `st=2019-12-31T07%3A17%3A31Z&se=2020-01-01T07%3A17%3A31Z&sp=racwdl&sv=2018-03-28&sr=c&sig=xxxxxxxxxxxxxxxxxxxxxxxxxx`';
var url = 'https://$accountName.blob.core.windows.net/$containerName/$blobName?$sasTokenContainerLevel';
var data = File(blobName).readAsBytesSync();
var dio = Dio();
try {
final response = await dio.put(
url,
data: data,
onSendProgress:
(int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
options: Options(
headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': 'text/plain',
})
);
print(response.data);
} catch (e) {
print(e);
}
Response response = await dio.get(url);
print(response.data);
}
Then, I ran it and got the result as the figure below.
The content of the uploaded file as blob is the json string encoded from a Uint8List bytes from the funtion readAsBytesSync.
I researched the description and the source code of dio, actually I found dio is only suitable for sending the request body of json format, not for raw content as request body.
Fig 1. The default transformer apply for POST method
Fig 2. https://github.com/flutterchina/dio/blob/master/dio/lib/src/transformer.dart
So to fix it is to write a custom transformer class PutTransformerForRawData instead of the default one to override the function transformRequest, as the code below.
import 'dart:typed_data';
class PutTransformerForRawData extends DefaultTransformer {
#override
Future<String> transformRequest(RequestOptions options) async {
if(options.data is Uint8List) {
return new String.fromCharCodes(options.data);
} else if(options.data is String) {
return options.data;
}
}
}
And to replace the default transformer via the code below.
var dio = Dio();
dio.transformer = PutTransformerForRawData();
Then, you can get the data via the code below.
var data = File(blobName).readAsBytesSync();
Or
var data = File(blobName).readAsStringSync();
Note: the custom transfer PutTransformerForRawData is only for uploading, please remove the download & print code Response response = await dio.get(url); print(response.data);, the default transformer seems to check the response body whether be json format, I got the exception as below when my uploaded file is my sample code.
Unhandled exception:
DioError [DioErrorType.DEFAULT]: FormatException: Unexpected character (at character 1)
import 'dart:typed_data';

How to get excel file from disc in angular2 via rest

I am using an angular 2 with Java background and communication between them is through REST. What I have to do is to create some excel file on button click and then to return that file in the user API.
REST looks like this:
#RequestMapping(value = "/some_path/{someId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public FileSystemResource exportSomeData(#PathVariable long someId, HttpServletResponse response) {
// ... create excel file data...
File file = new File(fileName);
response.addHeader("FILE_NAME", fileName);
FileNameResource fsr = new FileNameResource(file);
return fsr;
}
In angular (return of the REST, call works ok):
getFile(path:String) {
this.autthHttp.get(`some_path')
.map((response) => {
let blob = (response)['body'];
return {
data: new Blob([blob], {type: 'application/octet-stream'}),
filename: response.headers.get('FILE_NAME')
}
})
.subscribe(res => saveAs(res.data, res.filename))
}
The problem is that I got the file, it contains data, but it lost it's metadata (show some question mark characters instead of format excel well in cells). Does somebody knows what can be the problem?
Try to set the responseType to Blob and use RC5 blob response type:
getFile(path:String) {
this.autthHttp.get(`some_path', {responseType: ResponseContentType.Blob})
.map((response) => {
let blob = response.blob();
return {
data: new Blob([blob], {type: 'application/octet-stream'}),
filename: response.headers.get('FILE_NAME')
}
})
.subscribe(res => saveAs(res.data, res.filename))
}

Resources