Closed alignsoft closed 6 years ago
Wellllllllllllll, we all use Angular if we use this package BUTTTTTTT we all seem to be using different servers
I would just suggest Googling "Server-side FormData processing examples"
I mean, FormData is a standardized W3C HTML5 item. We should master working with it in general, regardless of this package and Angular.
I'm like an eyelash twitch away from closing this issue based on how I see this. Since I very first forked this code, my intension was to take this package from old school crap to updated techniques. You wanna stay stuck old school, go with the original package.
on windows server with iis i use webapi 2.0 and the endpoint is an http post
that uses a standard component
var streamProvider = new MultipartFormDataStreamProvider(ServerUploadFolder); await Request.Content.ReadAsMultipartAsync(streamProvider);
and then
foreach (MultipartFileData item in streamProvider.FileData) {
i have been meaning to put this code online but other things keep me busy....
The problem, for me, is that I'm responsible for front end development only (which is why we're using Angular), and I'm trying to keep guiding the entire team who are writing all the server side code and the entire stack to current technology, and there's always resistance, always that 'we know the old rusty, which should we use the new shiny'. I'm sure I'm not alone in my working environment.
Having anything to point to that says 'Here's something you can see and extrapolate from' is incredibly useful when dealing with a 'show don't tell' team. They are smart guys, and can figure things out if they can see an example of what they need to learn.
It's easy to say 'Google FooBar' when you have a working knowledge of what FooBar is composed of, and if Googling 'server side code for handling/receiving/extracting files from FormData POST data' had gotten me anything useful, I wouldn't be asking.
You mentioned earlier that you have (I think) a node.js server and Java code on two different application instances, and with @figuerres webapi 2.0 example that's three bits of reference code that would be very useful to someone without the server side experience you have.
Again - reducing the amount of friction required to adopt something like this goes a long way to driving adoption, and because this is new, there's not a lot of documentation with context that's easy to find. This clearly isn't about me wanting to stay 'old school', I've already made the jump, it's me needing a little guidance in breaking the inertia for the guys on the server side of my fence.
I'm going to try to make this as simple as possible for you:
<form method="post" enctype="multipart/form-data"></form>
IS 100% the same protocol as the FormData HTML5 class.
Have you ever, ever, ever, ever, in your career, sent files using enctype="multipart/form-data" ??? It's the saaaaaaaaaaaaaammmmmmmmmme exact protocol used when transmitting files using Javascript's FormData... It's multipart/form-data but instead of the <form>
tag transmitting the data, it's Javascript.
I feel it's spelled out in a basic education document, as seen here: https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript
(also, again, I like being dramatic and I'm not heated)
The problem isn't the front end - I have implemented angular-file, the browser works great, I can select files, I'm using FormData.append to add key/value pairs to send other required data back with the files so that the files can be associated with the correct items in the database, and those key/value pairs are extractable on the server side without any difficulty.
The filedata itself, while visible as a separate item in the network tab of the browser as base64encoded data doesn't seem to be extractable on the server side, and I don't know if that's because there's a problem sending it (however it's in the network payload as far as I can see), so I'm assuming that the problem is the guy's writing the server side code don't know how to extract the file data.
On the network tab in Chrome, I see this: data:image/jpeg/base64
Request URL:data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/...
And below it: api/
------WebKitFormBoundaryKfchX9MJnOAjMAn3
Content-Disposition: form-data; name:"file"; filename="Thumb2.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryKfchX9MJnOAjMAn3
Content-Disposition: form-data; name="groupID"
9003271
------WebKitFormBoundaryKfchX9MJnOAjMAn3
Content-Disposition: form-data; name="userID"
demouser
------WebKitFormBoundaryKfchX9MJnOAjMAn3--
The image data is complete - I can copy/paste that into a service that writes out a valid file, but I'm being told the file data isn't actually in the FormData I'm submitting, and I have nothing to point to for them to try.
It's entirely possible that we are doing everything exactly correctly, and there's a bug in my client side implementation, but I can't know that for certain either way at this point. I think I've implemented things correctly, and the server guys think they have implemented things correctly, and as the guy pushing the new shiny, the burden is on me to prove one way or the other.
Try to see if your server can process this than:
<form action="http://..." method="post" enctype="multipart/form-data">
<input type="file" name="file" />
</form>
Based on the article I provided, and my recent experience: Processing the form tag multipart/form-data, on the server side, is exactly like the FormData class. That is to say, on the server, you should see no difference.
The article I linked, is what you should be sharing with the people you are trying to "convince". At the bottom of the article is states:
Depending on the browser, sending form data through JavaScript can be easy or difficult. The FormData object is generally the answer, and don't hesitate to use a polyfill for it on legacy browsers
@alignsoft what is the back end server platform ? if it is IIS i can get my code and put it on line for your back end folks to check out.
if not IIS what are they using ?
you can also reach me as denny at figuerres dot com
hope that can help.
@figuerres Thanks Denny - it's Java on the backend. Cheers!
Here is the Java code we are using, I can't take the time to explain NOR strip out useless parts. But maybe it will help you along. Good luck
import java.io.IOException;
import java.io.InputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Types;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.aviorsciences.MysqlConnect;
import com.aviorsciences.HttpUtil.CustomResponses;
import com.aviorsciences.HttpUtil.exceptions.BadRequest;
import com.aviorsciences.HttpUtil.exceptions.Forbidden;
import com.aviorsciences.HttpUtil.exceptions.NotFound;
import com.aviorsciences.HttpUtil.firebase.Firebase;
import com.aviorsciences.HttpUtil.pojo.JsonBase;
import com.caringondemand.TapForCare._constants.ProcConstants;
import com.caringondemand.TapForCare._constants.S3Constants;
import com.caringondemand.TapForCare._constants.UrlConstants;
import com.caringondemand.TapForCare._enums.Permissions;
import com.caringondemand.TapForCare.endpoints.helpers.DashboardEndpointHelpers;
import com.caringondemand.TapForCare.endpoints.helpers.FacilityEndpointHelpers;
import com.caringondemand.TapForCare.endpoints.helpers.OrganizationalUnitEndpointHelpers;
import com.caringondemand.TapForCare.endpoints.helpers.UserEndpointHelpers;
import com.caringondemand.TapForCare.endpoints.pojo.Agency;
import com.caringondemand.TapForCare.endpoints.pojo.CaregiversByStatus;
import com.caringondemand.TapForCare.endpoints.pojo.DashboardInfo;
import com.caringondemand.TapForCare.endpoints.pojo.DashboardInfo2;
import com.caringondemand.TapForCare.endpoints.pojo.Facility;
import com.caringondemand.TapForCare.endpoints.pojo.FacilityArea;
import com.caringondemand.TapForCare.endpoints.pojo.MUserReq;
import com.caringondemand.TapForCare.endpoints.pojo.Roc;
import com.caringondemand.TapForCare.endpoints.pojo.RocVisitInfo;
import com.caringondemand.TapForCare.endpoints.pojo.RocsByStatus;
import com.caringondemand.TapForCare.endpoints.pojo.UserAccessIds;
import com.caringondemand.TapForCare.endpoints.pojo.UserFacility;
import com.caringondemand.TapForCare.endpoints.pojo.Wifi;
import com.caringondemand.TapForCare.endpoints.pojo.firebase.VisitInOut;
import com.caringondemand.TapForCare.utils.ArrayListUtil;
import com.caringondemand.TapForCare.utils.AwsUtil;
import com.caringondemand.TapForCare.utils.BadRequestUtil;
import com.caringondemand.TapForCare.utils.PermissionUtil;
import com.sun.jersey.api.core.ResourceContext;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;
@Path("/facility")
public class FacilityV1Endpoints {
@Context ResourceContext resCtx;
@Context
HttpServletRequest req;
@POST
@Path("/file")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public Response uploadFile (
@FormDataParam("file") InputStream fileInputStream,
@FormDataParam("file") FormDataContentDisposition fileContent,
@FormDataParam("path") String path,
@FormDataParam("id") Integer id) throws Exception {
MUserReq ruser = UserEndpointHelpers.getRequestUser(req);
if (!ruser.isGod()) {
if (!ruser.isFac())
PermissionUtil.ForbiddenRoleCreate(ruser.getRole(), Permissions.FILE);
}
//TODO:remove these lines when the below todo is done.
String fileName = fileContent.getFileName();
String key = fileName;
if (path.length() > 0)
key = path + "/" + fileName;
//TODO:remove this outer if statement once implemented, and create the path yourself.
if (id != null) {
try(MysqlConnect conn = new MysqlConnect(UrlConstants.FACILITY_DB);) {
UserAccessIds ids = UserEndpointHelpers.getAccessIds(conn, ruser);
if (!ruser.isGod()) ids.checkAccessForFacilityID(id);
}
path = UrlConstants.ENV.getS3BucketPath() + "/" + fileContent.getFileName();
}
AwsUtil aws = new AwsUtil();
aws.S3_UploadSingleFile(S3Constants.facilityBucket, key, fileInputStream);
return CustomResponses.succesfulResponse();
}
}
As using FormData to send files to a server is relatively new to Angular2 and the new HttpClient, I'm finding it difficult to know how to best receive files on the server. Not being able to view the file data payload on the client side (other than interrogating the network payload itself) is making it difficult to write server side code.
An examples of server code implementing a simple receiver would make adopting this approach much more accessible.