Popular New Releases in File Upload
uppy
Uppy 2.9.3
dropzone
Release v5.9.2
filepond
4.28.2
bootstrap-fileinput
Version 5.2.3
angular-file-upload
2.6.1
Popular Libraries in File Upload
by blueimp php
31080 MIT
File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.
by transloadit javascript
25143 MIT
The next open source file uploader for web browsers :dog:
by dropzone javascript
15704 NOASSERTION
Dropzone is an easy to use drag'n'drop library. It supports image previews and shows nice progress bars.
by pqina javascript
12102 MIT
🌊 A flexible and fun JavaScript file upload library
by danialfarid javascript
7979 MIT
Lightweight Angular directive to upload files with optional FileAPI shim for cross browser support
by kartik-v javascript
5024 NOASSERTION
An enhanced HTML 5 file input for Bootstrap 5.x/4.x./3.x with file preview, multiple selection, and more features.
by 23 javascript
4318 MIT
A JavaScript library for providing multiple simultaneous, stable, fault-tolerant and resumable/restartable uploads via the HTML5 File API.
by nervgh javascript
3487 MIT
[ALMOST NOT MAINTAINED] Angular File Upload is a module for the AngularJS framework
by flowjs javascript
2834 MIT
A JavaScript library providing multiple simultaneous, stable, fault-tolerant and resumable/restartable file uploads via the HTML5 File API.
Trending New libraries in File Upload
by felixonmars go
772 Apache-2.0
Re-upload of iikira/BaiduPCS-Go
by ahmed-aliraqi php
283
This package used to upload files using laravel-media-library before saving model.
by cheersmas typescript
186 MIT
A minimal Upload component for React.
by ryanto javascript
170 MIT
Upload files from your Next.js app to S3
by cloudinary-labs php
162 MIT
Laravel SDK for Cloudinary
by aquiladev javascript
110 MIT
GitHub Action for upload to IPFS. Supports Pinata, Infura pinning service as well as direct upload.
by pqina javascript
98 MIT
🔌 A handy FilePond adapter component for Svelte
by edeckers kotlin
92 MPL-2.0
Use this library to efficiently download and upload blobs in React Native.
by zhanyuzhang javascript
76
Tinypng without "Too many files uploaded at once" limit
Top Authors in File Upload
1
12 Libraries
15469
2
9 Libraries
670
3
8 Libraries
59
4
7 Libraries
343
5
6 Libraries
2433
6
6 Libraries
442
7
5 Libraries
21
8
4 Libraries
27
9
4 Libraries
27
10
4 Libraries
1859
1
12 Libraries
15469
2
9 Libraries
670
3
8 Libraries
59
4
7 Libraries
343
5
6 Libraries
2433
6
6 Libraries
442
7
5 Libraries
21
8
4 Libraries
27
9
4 Libraries
27
10
4 Libraries
1859
Trending Kits in File Upload
Here are some best React File Uploader Libraries. React File Uploader Libraries' use cases include Image Uploads, File Storage, Data Visualization, and Third-Party Services.
React file uploader libraries are libraries of code that enable developers to create and implement file-uploading functionality in React applications. These libraries typically handle the loading, displaying, and manipulation of files and provide features such as validation, progress tracking, and security.
Let us look at these libraries in detail below.
react-dropzone
- Allows users to drag and drop files directly into the browser window for uploading.
- Built-in support for previewing images and other file types before uploading.
- Multiple file uploads can be configured to accept multiple file types.
uppload
- Supports powerful image editing capabilities.
- Supports direct uploads to Amazon S3.
- Can be integrated with Cloudinary, allowing for fast, secure, and easy image and video processing.
react-filepond
- Supports serverless uploads.
- Supports basic image editing capabilities.
- Supports file type validation.
React-Dropzone-Component
- Offers an intuitive, declarative API.
- Provides an optional image preview feature.
- Offers a wide range of customization options.
react-uploady
- Multiple authentication methods.
- Built-in security features.
- Support for multiple languages.
react-dropzone-uploader
- Supports both single and multiple file uploads.
- Allows for automatic resizing of images as they're uploaded.
- Supports server-side file validation.
react-firebase-file-uploader
- Upload files directly to Firebase Storage, not just the web server.
- Easy way to track and visualize the progress of file uploads in real time.
- Lets you customize the look and feel of your uploader.
react_file_uploader
- Provides a robust, highly configurable uploader.
- Supports chunked file uploads.
- Can select multiple files to upload at once.
Trending Discussions on File Upload
Azure ASP.NET Core web api returns 404 for proxied multipart/form-data request
php ajax file upload not working - partial file upload error
How to get data point label using click in plotly
How to upload a stream to S3 with AWS SDK v3
Spring Boot 2.5.x: Required request part 'file' is not present
How to get a upload button in swagger for IFormFile combined with other properties?
Problem dealing with a space when moving JSON to Python
Java can't upload file with @Pathvariable optional
Antd File upload not getting reset
Load byte[] Property of Class Only When Needed
QUESTION
Azure ASP.NET Core web api returns 404 for proxied multipart/form-data request
Asked 2022-Mar-11 at 08:40I'm new to Azure and trying to set up my nextjs client app and my ASP.NET Core backend app. Everything seems to play well now, except for file uploads. It's working on localhost, but in production the backend returns a 404 web page (attached image) before reaching the actual API endpoint. I've also successfully tested to make a multipart/form-data POST request in Postman from my computer.
The way I implemented this is that I'm proxying the upload from the browser through an api route (client's server side) to the backend. I have to go via the client server side to append a Bearer token from a httpOnly cookie.
I've enabled CORS in Startup.cs:
1app.UseCors(builder => { builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod(); });
2
The frontend and backend apps are running in individual services and I've tried to enable CORS in the Azure portal as well, but there I could only allow origins, not headers and methods? The error message doesn't indicate CORS problems, but I just wanted make sure..
As far as I can see the requests look good, with correct URLs and origins. I suspect I'm missing some config in azure, but I didn't get any further by following the hints in the error message.
Any suggestions to what may cause this? Or where I can start looking. I'm not quite sure where to look for log output for this issue.
ANSWER
Answered 2022-Mar-10 at 06:35Cross-Origin Resource Sharing (CORS) allows JavaScript code running in a browser on an external host to interact with your backend.
To allow all, use "*" and remove all other origins from the list.
I could only allow origins, not headers and methods?
Add the below configuration in your web.config
file to allow headers and methods.
1app.UseCors(builder => { builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod(); });
2<system.webServer>
3 <httpProtocol>
4 <customHeaders>
5 <add name="Access-Control-Allow-Origin" value="*" />
6 <add name="Access-Control-Allow-Headers" value="Content-Type" />
7 <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
8 </customHeaders>
9 </httpProtocol>
10</system.webServer>
11
Add the below snippet in web.config=><system.webServer> =>handlers tag
1app.UseCors(builder => { builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod(); });
2<system.webServer>
3 <httpProtocol>
4 <customHeaders>
5 <add name="Access-Control-Allow-Origin" value="*" />
6 <add name="Access-Control-Allow-Headers" value="Content-Type" />
7 <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
8 </customHeaders>
9 </httpProtocol>
10</system.webServer>
11<?xml version="1.0" encoding="utf-8"?>
12<configuration>
13 <location path="." inheritInChildApplications="false">
14 <system.webServer>
15 <handlers>
16 <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
17 </handlers>
18 <aspNetCore processPath="dotnet" arguments=".\yourURI.dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" hostingModel="InProcess" />
19 </system.webServer>
20 </location>
21</configuration>
22
- Make sure the routing is done properly
[Route("api/[controller]")] should be in your controller class.
client cache is still pointing to the domain to ols ip address. clear the cache by running the command ipconfig/flushdns
Please refer Custom domain has not been configured inside Azure ,Azure WebApps Custom Domain 404 error - Flush DNS and SO Thread for more information
QUESTION
php ajax file upload not working - partial file upload error
Asked 2022-Mar-02 at 11:40I've written code for uploading a file along with other form inputs using html, ajax and php. I'm submitting the form using ajax. Everything is working in one server, but when I moved the code to a new server, I keep getting PARTIAL FILE UPLOAD ERROR.
Sample code is given below
HTML:
1<form id="gal-form" class="form-gallery" enctype="multipart/form-data">
2 <input type="hidden" id="gal_id" name="id" value="">
3 <div class="up-types">
4 <div class="input-group mb-3 display-none check-links">
5 <span class="input-group-text">Links to</span>
6 <input type="text" value="ebooks" disabled="">
7 <input type="text" name="links[]" class="form-control" data-type="ebooks" id="links_to_3" value="">
8 </div>
9 <div class="input-group mb-3 display-none check-links">
10 <span class="input-group-text">Links to</span>
11 <input type="text" value="handbooks" disabled="">
12 <input type="text" name="links[]" class="form-control" data-type="handbooks" id="links_to_4" value="">
13 </div>
14 <div class="input-group mb-3 display-none check-links">
15 <span class="input-group-text">Links to</span>
16 <input type="text" value="manuals" disabled="">
17 <input type="text" name="links[]" class="form-control" data-type="manuals" id="links_to_5" value="">
18 </div>
19 </div>
20 <div class="form-group">
21 <label for="gal_title">Title</label>
22 <input type="text" class="form-control" id="gal_title" name="title" placeholder="Add a title here..">
23 </div>
24 <div class="form-group">
25 <label for="gal_title">Category</label>
26 <input id="gallery_tags" class="form-control" name="tags[]" type="text" value="" placeholder="Add a category here..">
27 </div>
28 <div class="form-group">
29 <label>File upload <span class="text-danger">*Only PDF, MP4, WEBM, OGG, JPG, JPEG, &amp; PNG files are allowed. Please try to upload images/videos of a specific aspect ratio</span></label>
30 <input type="file" name="gal" id="gal-file" class="file-upload-default">
31 <div class="input-group col-xs-12">
32 <input type="text" class="form-control file-upload-info" disabled="" placeholder="Upload File">
33 <span class="input-group-append">
34 <button class="file-upload-browse btn btn-primary" type="button">Browse</button>
35 </span>
36 </div>
37 </div>
38 <div class="form-group">
39 <label for="event_text">Description</label>
40 <textarea class="form-control" id="media_desc" name="desc" rows="4" aria-hidden="true"></textarea>
41 </div>
42 <button type="submit" id="gal-button" class="btn btn-primary mr-2">Submit</button>
43</form>
44
I've to set some parameters from javascript, so,
1<form id="gal-form" class="form-gallery" enctype="multipart/form-data">
2 <input type="hidden" id="gal_id" name="id" value="">
3 <div class="up-types">
4 <div class="input-group mb-3 display-none check-links">
5 <span class="input-group-text">Links to</span>
6 <input type="text" value="ebooks" disabled="">
7 <input type="text" name="links[]" class="form-control" data-type="ebooks" id="links_to_3" value="">
8 </div>
9 <div class="input-group mb-3 display-none check-links">
10 <span class="input-group-text">Links to</span>
11 <input type="text" value="handbooks" disabled="">
12 <input type="text" name="links[]" class="form-control" data-type="handbooks" id="links_to_4" value="">
13 </div>
14 <div class="input-group mb-3 display-none check-links">
15 <span class="input-group-text">Links to</span>
16 <input type="text" value="manuals" disabled="">
17 <input type="text" name="links[]" class="form-control" data-type="manuals" id="links_to_5" value="">
18 </div>
19 </div>
20 <div class="form-group">
21 <label for="gal_title">Title</label>
22 <input type="text" class="form-control" id="gal_title" name="title" placeholder="Add a title here..">
23 </div>
24 <div class="form-group">
25 <label for="gal_title">Category</label>
26 <input id="gallery_tags" class="form-control" name="tags[]" type="text" value="" placeholder="Add a category here..">
27 </div>
28 <div class="form-group">
29 <label>File upload <span class="text-danger">*Only PDF, MP4, WEBM, OGG, JPG, JPEG, &amp; PNG files are allowed. Please try to upload images/videos of a specific aspect ratio</span></label>
30 <input type="file" name="gal" id="gal-file" class="file-upload-default">
31 <div class="input-group col-xs-12">
32 <input type="text" class="form-control file-upload-info" disabled="" placeholder="Upload File">
33 <span class="input-group-append">
34 <button class="file-upload-browse btn btn-primary" type="button">Browse</button>
35 </span>
36 </div>
37 </div>
38 <div class="form-group">
39 <label for="event_text">Description</label>
40 <textarea class="form-control" id="media_desc" name="desc" rows="4" aria-hidden="true"></textarea>
41 </div>
42 <button type="submit" id="gal-button" class="btn btn-primary mr-2">Submit</button>
43</form>
44$("#gal-form").on('submit', function(e) {
45 e.preventDefault();
46 var desc = "Some description here";
47
48 if ($('#gal_title').val() == '') {
49 $('#display-msg').html('<span style="color:red">Please enter title name...</span>');
50 return false;
51 } else if ($('#gal-file').get(0).files.length === 0 && !desc) {
52 $('#display-msg').html('<span style="color:red">Please enter a description or choose a file to upload...</span>');
53 return false;
54 }
55
56 var formData = new FormData(this);
57 var values = $("input[name='links[]']:enabled").map(function() {
58 let id = this.id.split("_").pop();
59 let link = $(this).data("type");
60 if (this.value) {
61 link += "/" + this.value;
62 }
63 return {
64 id: id,
65 link: link
66 };
67 }).get();
68 formData.append('links_to', JSON.stringify(values));
69 formData.set('desc',desc);
70
71 $.ajax({
72 type: 'POST',
73 url: 'url',
74 data: formData,
75 dataType: 'json',
76 contentType: false,
77 cache: false,
78 processData: false,
79 success: function(obj) {
80 if (obj.success) {
81 window.location.reload();
82 } else {
83 alertItem(obj.error);
84 }
85 },
86 error: function(request, status, error) {
87 alertItem(request.responseText);
88 }
89 });
90});
91
And in PHP,
1<form id="gal-form" class="form-gallery" enctype="multipart/form-data">
2 <input type="hidden" id="gal_id" name="id" value="">
3 <div class="up-types">
4 <div class="input-group mb-3 display-none check-links">
5 <span class="input-group-text">Links to</span>
6 <input type="text" value="ebooks" disabled="">
7 <input type="text" name="links[]" class="form-control" data-type="ebooks" id="links_to_3" value="">
8 </div>
9 <div class="input-group mb-3 display-none check-links">
10 <span class="input-group-text">Links to</span>
11 <input type="text" value="handbooks" disabled="">
12 <input type="text" name="links[]" class="form-control" data-type="handbooks" id="links_to_4" value="">
13 </div>
14 <div class="input-group mb-3 display-none check-links">
15 <span class="input-group-text">Links to</span>
16 <input type="text" value="manuals" disabled="">
17 <input type="text" name="links[]" class="form-control" data-type="manuals" id="links_to_5" value="">
18 </div>
19 </div>
20 <div class="form-group">
21 <label for="gal_title">Title</label>
22 <input type="text" class="form-control" id="gal_title" name="title" placeholder="Add a title here..">
23 </div>
24 <div class="form-group">
25 <label for="gal_title">Category</label>
26 <input id="gallery_tags" class="form-control" name="tags[]" type="text" value="" placeholder="Add a category here..">
27 </div>
28 <div class="form-group">
29 <label>File upload <span class="text-danger">*Only PDF, MP4, WEBM, OGG, JPG, JPEG, &amp; PNG files are allowed. Please try to upload images/videos of a specific aspect ratio</span></label>
30 <input type="file" name="gal" id="gal-file" class="file-upload-default">
31 <div class="input-group col-xs-12">
32 <input type="text" class="form-control file-upload-info" disabled="" placeholder="Upload File">
33 <span class="input-group-append">
34 <button class="file-upload-browse btn btn-primary" type="button">Browse</button>
35 </span>
36 </div>
37 </div>
38 <div class="form-group">
39 <label for="event_text">Description</label>
40 <textarea class="form-control" id="media_desc" name="desc" rows="4" aria-hidden="true"></textarea>
41 </div>
42 <button type="submit" id="gal-button" class="btn btn-primary mr-2">Submit</button>
43</form>
44$("#gal-form").on('submit', function(e) {
45 e.preventDefault();
46 var desc = "Some description here";
47
48 if ($('#gal_title').val() == '') {
49 $('#display-msg').html('<span style="color:red">Please enter title name...</span>');
50 return false;
51 } else if ($('#gal-file').get(0).files.length === 0 && !desc) {
52 $('#display-msg').html('<span style="color:red">Please enter a description or choose a file to upload...</span>');
53 return false;
54 }
55
56 var formData = new FormData(this);
57 var values = $("input[name='links[]']:enabled").map(function() {
58 let id = this.id.split("_").pop();
59 let link = $(this).data("type");
60 if (this.value) {
61 link += "/" + this.value;
62 }
63 return {
64 id: id,
65 link: link
66 };
67 }).get();
68 formData.append('links_to', JSON.stringify(values));
69 formData.set('desc',desc);
70
71 $.ajax({
72 type: 'POST',
73 url: 'url',
74 data: formData,
75 dataType: 'json',
76 contentType: false,
77 cache: false,
78 processData: false,
79 success: function(obj) {
80 if (obj.success) {
81 window.location.reload();
82 } else {
83 alertItem(obj.error);
84 }
85 },
86 error: function(request, status, error) {
87 alertItem(request.responseText);
88 }
89 });
90});
91$uploadStatus = 1;
92$data = array();
93if(!empty($_FILES["gal"]["name"])){
94 $file_name = pathinfo(basename($_FILES["gal"]["name"]),PATHINFO_FILENAME);
95 $fileType = pathinfo(basename($_FILES["gal"]["name"]), PATHINFO_EXTENSION);
96
97 $fileName = $this->generateSlug($file_name).'_'.time().'.'.$fileType;
98 $targetFilePath = $fileName;
99
100 $allowTypes = array('pdf', 'mp4', 'webm', 'ogg', 'jpg', 'png', 'jpeg');
101 if(in_array(strtolower($fileType), $allowTypes)){
102 if(move_uploaded_file($_FILES["gal"]["tmp_name"], $targetFilePath)){
103 $data['file'] = $fileName;
104 }else{
105 $uploadStatus = 0;
106 return array('error'=>$_FILES["error"]));
107 }
108 }else{
109 $uploadStatus = 0;
110 return array('error'=>'Sorry, only PDF, MP4, WEBM, OGG, JPG, JPEG, & PNG files are allowed to upload.');
111 }
112}
113
114if($uploadStatus == 1){
115 //Add to database
116}
117
Uploading will work if submit the form directly from PHP. I've looked through and compared apache and php configurations to check if there is anything missing. Below are the server configurations of apache and php. Uploading works in both Server1 and Server2.
Server 1:
1<form id="gal-form" class="form-gallery" enctype="multipart/form-data">
2 <input type="hidden" id="gal_id" name="id" value="">
3 <div class="up-types">
4 <div class="input-group mb-3 display-none check-links">
5 <span class="input-group-text">Links to</span>
6 <input type="text" value="ebooks" disabled="">
7 <input type="text" name="links[]" class="form-control" data-type="ebooks" id="links_to_3" value="">
8 </div>
9 <div class="input-group mb-3 display-none check-links">
10 <span class="input-group-text">Links to</span>
11 <input type="text" value="handbooks" disabled="">
12 <input type="text" name="links[]" class="form-control" data-type="handbooks" id="links_to_4" value="">
13 </div>
14 <div class="input-group mb-3 display-none check-links">
15 <span class="input-group-text">Links to</span>
16 <input type="text" value="manuals" disabled="">
17 <input type="text" name="links[]" class="form-control" data-type="manuals" id="links_to_5" value="">
18 </div>
19 </div>
20 <div class="form-group">
21 <label for="gal_title">Title</label>
22 <input type="text" class="form-control" id="gal_title" name="title" placeholder="Add a title here..">
23 </div>
24 <div class="form-group">
25 <label for="gal_title">Category</label>
26 <input id="gallery_tags" class="form-control" name="tags[]" type="text" value="" placeholder="Add a category here..">
27 </div>
28 <div class="form-group">
29 <label>File upload <span class="text-danger">*Only PDF, MP4, WEBM, OGG, JPG, JPEG, &amp; PNG files are allowed. Please try to upload images/videos of a specific aspect ratio</span></label>
30 <input type="file" name="gal" id="gal-file" class="file-upload-default">
31 <div class="input-group col-xs-12">
32 <input type="text" class="form-control file-upload-info" disabled="" placeholder="Upload File">
33 <span class="input-group-append">
34 <button class="file-upload-browse btn btn-primary" type="button">Browse</button>
35 </span>
36 </div>
37 </div>
38 <div class="form-group">
39 <label for="event_text">Description</label>
40 <textarea class="form-control" id="media_desc" name="desc" rows="4" aria-hidden="true"></textarea>
41 </div>
42 <button type="submit" id="gal-button" class="btn btn-primary mr-2">Submit</button>
43</form>
44$("#gal-form").on('submit', function(e) {
45 e.preventDefault();
46 var desc = "Some description here";
47
48 if ($('#gal_title').val() == '') {
49 $('#display-msg').html('<span style="color:red">Please enter title name...</span>');
50 return false;
51 } else if ($('#gal-file').get(0).files.length === 0 && !desc) {
52 $('#display-msg').html('<span style="color:red">Please enter a description or choose a file to upload...</span>');
53 return false;
54 }
55
56 var formData = new FormData(this);
57 var values = $("input[name='links[]']:enabled").map(function() {
58 let id = this.id.split("_").pop();
59 let link = $(this).data("type");
60 if (this.value) {
61 link += "/" + this.value;
62 }
63 return {
64 id: id,
65 link: link
66 };
67 }).get();
68 formData.append('links_to', JSON.stringify(values));
69 formData.set('desc',desc);
70
71 $.ajax({
72 type: 'POST',
73 url: 'url',
74 data: formData,
75 dataType: 'json',
76 contentType: false,
77 cache: false,
78 processData: false,
79 success: function(obj) {
80 if (obj.success) {
81 window.location.reload();
82 } else {
83 alertItem(obj.error);
84 }
85 },
86 error: function(request, status, error) {
87 alertItem(request.responseText);
88 }
89 });
90});
91$uploadStatus = 1;
92$data = array();
93if(!empty($_FILES["gal"]["name"])){
94 $file_name = pathinfo(basename($_FILES["gal"]["name"]),PATHINFO_FILENAME);
95 $fileType = pathinfo(basename($_FILES["gal"]["name"]), PATHINFO_EXTENSION);
96
97 $fileName = $this->generateSlug($file_name).'_'.time().'.'.$fileType;
98 $targetFilePath = $fileName;
99
100 $allowTypes = array('pdf', 'mp4', 'webm', 'ogg', 'jpg', 'png', 'jpeg');
101 if(in_array(strtolower($fileType), $allowTypes)){
102 if(move_uploaded_file($_FILES["gal"]["tmp_name"], $targetFilePath)){
103 $data['file'] = $fileName;
104 }else{
105 $uploadStatus = 0;
106 return array('error'=>$_FILES["error"]));
107 }
108 }else{
109 $uploadStatus = 0;
110 return array('error'=>'Sorry, only PDF, MP4, WEBM, OGG, JPG, JPEG, & PNG files are allowed to upload.');
111 }
112}
113
114if($uploadStatus == 1){
115 //Add to database
116}
117Apache/2.4.6 (RHEL 7.9)
118PHP 7.3.29
119
Server 2:
1<form id="gal-form" class="form-gallery" enctype="multipart/form-data">
2 <input type="hidden" id="gal_id" name="id" value="">
3 <div class="up-types">
4 <div class="input-group mb-3 display-none check-links">
5 <span class="input-group-text">Links to</span>
6 <input type="text" value="ebooks" disabled="">
7 <input type="text" name="links[]" class="form-control" data-type="ebooks" id="links_to_3" value="">
8 </div>
9 <div class="input-group mb-3 display-none check-links">
10 <span class="input-group-text">Links to</span>
11 <input type="text" value="handbooks" disabled="">
12 <input type="text" name="links[]" class="form-control" data-type="handbooks" id="links_to_4" value="">
13 </div>
14 <div class="input-group mb-3 display-none check-links">
15 <span class="input-group-text">Links to</span>
16 <input type="text" value="manuals" disabled="">
17 <input type="text" name="links[]" class="form-control" data-type="manuals" id="links_to_5" value="">
18 </div>
19 </div>
20 <div class="form-group">
21 <label for="gal_title">Title</label>
22 <input type="text" class="form-control" id="gal_title" name="title" placeholder="Add a title here..">
23 </div>
24 <div class="form-group">
25 <label for="gal_title">Category</label>
26 <input id="gallery_tags" class="form-control" name="tags[]" type="text" value="" placeholder="Add a category here..">
27 </div>
28 <div class="form-group">
29 <label>File upload <span class="text-danger">*Only PDF, MP4, WEBM, OGG, JPG, JPEG, &amp; PNG files are allowed. Please try to upload images/videos of a specific aspect ratio</span></label>
30 <input type="file" name="gal" id="gal-file" class="file-upload-default">
31 <div class="input-group col-xs-12">
32 <input type="text" class="form-control file-upload-info" disabled="" placeholder="Upload File">
33 <span class="input-group-append">
34 <button class="file-upload-browse btn btn-primary" type="button">Browse</button>
35 </span>
36 </div>
37 </div>
38 <div class="form-group">
39 <label for="event_text">Description</label>
40 <textarea class="form-control" id="media_desc" name="desc" rows="4" aria-hidden="true"></textarea>
41 </div>
42 <button type="submit" id="gal-button" class="btn btn-primary mr-2">Submit</button>
43</form>
44$("#gal-form").on('submit', function(e) {
45 e.preventDefault();
46 var desc = "Some description here";
47
48 if ($('#gal_title').val() == '') {
49 $('#display-msg').html('<span style="color:red">Please enter title name...</span>');
50 return false;
51 } else if ($('#gal-file').get(0).files.length === 0 && !desc) {
52 $('#display-msg').html('<span style="color:red">Please enter a description or choose a file to upload...</span>');
53 return false;
54 }
55
56 var formData = new FormData(this);
57 var values = $("input[name='links[]']:enabled").map(function() {
58 let id = this.id.split("_").pop();
59 let link = $(this).data("type");
60 if (this.value) {
61 link += "/" + this.value;
62 }
63 return {
64 id: id,
65 link: link
66 };
67 }).get();
68 formData.append('links_to', JSON.stringify(values));
69 formData.set('desc',desc);
70
71 $.ajax({
72 type: 'POST',
73 url: 'url',
74 data: formData,
75 dataType: 'json',
76 contentType: false,
77 cache: false,
78 processData: false,
79 success: function(obj) {
80 if (obj.success) {
81 window.location.reload();
82 } else {
83 alertItem(obj.error);
84 }
85 },
86 error: function(request, status, error) {
87 alertItem(request.responseText);
88 }
89 });
90});
91$uploadStatus = 1;
92$data = array();
93if(!empty($_FILES["gal"]["name"])){
94 $file_name = pathinfo(basename($_FILES["gal"]["name"]),PATHINFO_FILENAME);
95 $fileType = pathinfo(basename($_FILES["gal"]["name"]), PATHINFO_EXTENSION);
96
97 $fileName = $this->generateSlug($file_name).'_'.time().'.'.$fileType;
98 $targetFilePath = $fileName;
99
100 $allowTypes = array('pdf', 'mp4', 'webm', 'ogg', 'jpg', 'png', 'jpeg');
101 if(in_array(strtolower($fileType), $allowTypes)){
102 if(move_uploaded_file($_FILES["gal"]["tmp_name"], $targetFilePath)){
103 $data['file'] = $fileName;
104 }else{
105 $uploadStatus = 0;
106 return array('error'=>$_FILES["error"]));
107 }
108 }else{
109 $uploadStatus = 0;
110 return array('error'=>'Sorry, only PDF, MP4, WEBM, OGG, JPG, JPEG, & PNG files are allowed to upload.');
111 }
112}
113
114if($uploadStatus == 1){
115 //Add to database
116}
117Apache/2.4.6 (RHEL 7.9)
118PHP 7.3.29
119Apache/2.4.37 (RHEL 8.4)
120PHP 7.4.19
121
Server 3 (New Server):
1<form id="gal-form" class="form-gallery" enctype="multipart/form-data">
2 <input type="hidden" id="gal_id" name="id" value="">
3 <div class="up-types">
4 <div class="input-group mb-3 display-none check-links">
5 <span class="input-group-text">Links to</span>
6 <input type="text" value="ebooks" disabled="">
7 <input type="text" name="links[]" class="form-control" data-type="ebooks" id="links_to_3" value="">
8 </div>
9 <div class="input-group mb-3 display-none check-links">
10 <span class="input-group-text">Links to</span>
11 <input type="text" value="handbooks" disabled="">
12 <input type="text" name="links[]" class="form-control" data-type="handbooks" id="links_to_4" value="">
13 </div>
14 <div class="input-group mb-3 display-none check-links">
15 <span class="input-group-text">Links to</span>
16 <input type="text" value="manuals" disabled="">
17 <input type="text" name="links[]" class="form-control" data-type="manuals" id="links_to_5" value="">
18 </div>
19 </div>
20 <div class="form-group">
21 <label for="gal_title">Title</label>
22 <input type="text" class="form-control" id="gal_title" name="title" placeholder="Add a title here..">
23 </div>
24 <div class="form-group">
25 <label for="gal_title">Category</label>
26 <input id="gallery_tags" class="form-control" name="tags[]" type="text" value="" placeholder="Add a category here..">
27 </div>
28 <div class="form-group">
29 <label>File upload <span class="text-danger">*Only PDF, MP4, WEBM, OGG, JPG, JPEG, &amp; PNG files are allowed. Please try to upload images/videos of a specific aspect ratio</span></label>
30 <input type="file" name="gal" id="gal-file" class="file-upload-default">
31 <div class="input-group col-xs-12">
32 <input type="text" class="form-control file-upload-info" disabled="" placeholder="Upload File">
33 <span class="input-group-append">
34 <button class="file-upload-browse btn btn-primary" type="button">Browse</button>
35 </span>
36 </div>
37 </div>
38 <div class="form-group">
39 <label for="event_text">Description</label>
40 <textarea class="form-control" id="media_desc" name="desc" rows="4" aria-hidden="true"></textarea>
41 </div>
42 <button type="submit" id="gal-button" class="btn btn-primary mr-2">Submit</button>
43</form>
44$("#gal-form").on('submit', function(e) {
45 e.preventDefault();
46 var desc = "Some description here";
47
48 if ($('#gal_title').val() == '') {
49 $('#display-msg').html('<span style="color:red">Please enter title name...</span>');
50 return false;
51 } else if ($('#gal-file').get(0).files.length === 0 && !desc) {
52 $('#display-msg').html('<span style="color:red">Please enter a description or choose a file to upload...</span>');
53 return false;
54 }
55
56 var formData = new FormData(this);
57 var values = $("input[name='links[]']:enabled").map(function() {
58 let id = this.id.split("_").pop();
59 let link = $(this).data("type");
60 if (this.value) {
61 link += "/" + this.value;
62 }
63 return {
64 id: id,
65 link: link
66 };
67 }).get();
68 formData.append('links_to', JSON.stringify(values));
69 formData.set('desc',desc);
70
71 $.ajax({
72 type: 'POST',
73 url: 'url',
74 data: formData,
75 dataType: 'json',
76 contentType: false,
77 cache: false,
78 processData: false,
79 success: function(obj) {
80 if (obj.success) {
81 window.location.reload();
82 } else {
83 alertItem(obj.error);
84 }
85 },
86 error: function(request, status, error) {
87 alertItem(request.responseText);
88 }
89 });
90});
91$uploadStatus = 1;
92$data = array();
93if(!empty($_FILES["gal"]["name"])){
94 $file_name = pathinfo(basename($_FILES["gal"]["name"]),PATHINFO_FILENAME);
95 $fileType = pathinfo(basename($_FILES["gal"]["name"]), PATHINFO_EXTENSION);
96
97 $fileName = $this->generateSlug($file_name).'_'.time().'.'.$fileType;
98 $targetFilePath = $fileName;
99
100 $allowTypes = array('pdf', 'mp4', 'webm', 'ogg', 'jpg', 'png', 'jpeg');
101 if(in_array(strtolower($fileType), $allowTypes)){
102 if(move_uploaded_file($_FILES["gal"]["tmp_name"], $targetFilePath)){
103 $data['file'] = $fileName;
104 }else{
105 $uploadStatus = 0;
106 return array('error'=>$_FILES["error"]));
107 }
108 }else{
109 $uploadStatus = 0;
110 return array('error'=>'Sorry, only PDF, MP4, WEBM, OGG, JPG, JPEG, & PNG files are allowed to upload.');
111 }
112}
113
114if($uploadStatus == 1){
115 //Add to database
116}
117Apache/2.4.6 (RHEL 7.9)
118PHP 7.3.29
119Apache/2.4.37 (RHEL 8.4)
120PHP 7.4.19
121Apache/2.4.46 (RHEL 7.9)
122PHP 7.4.12
123
I tried to close the connection by setting header("Connection: close");
, increased max_upload_size
, post_max_size
but no use.
What could be a possible reason for this?
Sample payload is also given below:
1<form id="gal-form" class="form-gallery" enctype="multipart/form-data">
2 <input type="hidden" id="gal_id" name="id" value="">
3 <div class="up-types">
4 <div class="input-group mb-3 display-none check-links">
5 <span class="input-group-text">Links to</span>
6 <input type="text" value="ebooks" disabled="">
7 <input type="text" name="links[]" class="form-control" data-type="ebooks" id="links_to_3" value="">
8 </div>
9 <div class="input-group mb-3 display-none check-links">
10 <span class="input-group-text">Links to</span>
11 <input type="text" value="handbooks" disabled="">
12 <input type="text" name="links[]" class="form-control" data-type="handbooks" id="links_to_4" value="">
13 </div>
14 <div class="input-group mb-3 display-none check-links">
15 <span class="input-group-text">Links to</span>
16 <input type="text" value="manuals" disabled="">
17 <input type="text" name="links[]" class="form-control" data-type="manuals" id="links_to_5" value="">
18 </div>
19 </div>
20 <div class="form-group">
21 <label for="gal_title">Title</label>
22 <input type="text" class="form-control" id="gal_title" name="title" placeholder="Add a title here..">
23 </div>
24 <div class="form-group">
25 <label for="gal_title">Category</label>
26 <input id="gallery_tags" class="form-control" name="tags[]" type="text" value="" placeholder="Add a category here..">
27 </div>
28 <div class="form-group">
29 <label>File upload <span class="text-danger">*Only PDF, MP4, WEBM, OGG, JPG, JPEG, &amp; PNG files are allowed. Please try to upload images/videos of a specific aspect ratio</span></label>
30 <input type="file" name="gal" id="gal-file" class="file-upload-default">
31 <div class="input-group col-xs-12">
32 <input type="text" class="form-control file-upload-info" disabled="" placeholder="Upload File">
33 <span class="input-group-append">
34 <button class="file-upload-browse btn btn-primary" type="button">Browse</button>
35 </span>
36 </div>
37 </div>
38 <div class="form-group">
39 <label for="event_text">Description</label>
40 <textarea class="form-control" id="media_desc" name="desc" rows="4" aria-hidden="true"></textarea>
41 </div>
42 <button type="submit" id="gal-button" class="btn btn-primary mr-2">Submit</button>
43</form>
44$("#gal-form").on('submit', function(e) {
45 e.preventDefault();
46 var desc = "Some description here";
47
48 if ($('#gal_title').val() == '') {
49 $('#display-msg').html('<span style="color:red">Please enter title name...</span>');
50 return false;
51 } else if ($('#gal-file').get(0).files.length === 0 && !desc) {
52 $('#display-msg').html('<span style="color:red">Please enter a description or choose a file to upload...</span>');
53 return false;
54 }
55
56 var formData = new FormData(this);
57 var values = $("input[name='links[]']:enabled").map(function() {
58 let id = this.id.split("_").pop();
59 let link = $(this).data("type");
60 if (this.value) {
61 link += "/" + this.value;
62 }
63 return {
64 id: id,
65 link: link
66 };
67 }).get();
68 formData.append('links_to', JSON.stringify(values));
69 formData.set('desc',desc);
70
71 $.ajax({
72 type: 'POST',
73 url: 'url',
74 data: formData,
75 dataType: 'json',
76 contentType: false,
77 cache: false,
78 processData: false,
79 success: function(obj) {
80 if (obj.success) {
81 window.location.reload();
82 } else {
83 alertItem(obj.error);
84 }
85 },
86 error: function(request, status, error) {
87 alertItem(request.responseText);
88 }
89 });
90});
91$uploadStatus = 1;
92$data = array();
93if(!empty($_FILES["gal"]["name"])){
94 $file_name = pathinfo(basename($_FILES["gal"]["name"]),PATHINFO_FILENAME);
95 $fileType = pathinfo(basename($_FILES["gal"]["name"]), PATHINFO_EXTENSION);
96
97 $fileName = $this->generateSlug($file_name).'_'.time().'.'.$fileType;
98 $targetFilePath = $fileName;
99
100 $allowTypes = array('pdf', 'mp4', 'webm', 'ogg', 'jpg', 'png', 'jpeg');
101 if(in_array(strtolower($fileType), $allowTypes)){
102 if(move_uploaded_file($_FILES["gal"]["tmp_name"], $targetFilePath)){
103 $data['file'] = $fileName;
104 }else{
105 $uploadStatus = 0;
106 return array('error'=>$_FILES["error"]));
107 }
108 }else{
109 $uploadStatus = 0;
110 return array('error'=>'Sorry, only PDF, MP4, WEBM, OGG, JPG, JPEG, & PNG files are allowed to upload.');
111 }
112}
113
114if($uploadStatus == 1){
115 //Add to database
116}
117Apache/2.4.6 (RHEL 7.9)
118PHP 7.3.29
119Apache/2.4.37 (RHEL 8.4)
120PHP 7.4.19
121Apache/2.4.46 (RHEL 7.9)
122PHP 7.4.12
123------WebKitFormBoundaryj7GC6KVa5gPA46RP
124Content-Disposition: form-data; name="id"
125
126
127------WebKitFormBoundaryj7GC6KVa5gPA46RP
128Content-Disposition: form-data; name="category[]"
129
1301
131------WebKitFormBoundaryj7GC6KVa5gPA46RP
132Content-Disposition: form-data; name="links[]"
133
134
135------WebKitFormBoundaryj7GC6KVa5gPA46RP
136Content-Disposition: form-data; name="title"
137
138Test
139------WebKitFormBoundaryj7GC6KVa5gPA46RP
140Content-Disposition: form-data; name="tags[]"
141
142Cat
143------WebKitFormBoundaryj7GC6KVa5gPA46RP
144Content-Disposition: form-data; name="gal"; filename="not.png"
145Content-Type: image/png
146
147
148------WebKitFormBoundaryj7GC6KVa5gPA46RP
149Content-Disposition: form-data; name="desc"
150
151<p>Test description</p>
152------WebKitFormBoundaryj7GC6KVa5gPA46RP
153Content-Disposition: form-data; name="links_to"
154
155[{"id":"1","link":"photo"}]
156------WebKitFormBoundaryj7GC6KVa5gPA46RP--
157
ANSWER
Answered 2022-Mar-02 at 11:40I recently found that the problem is due to Mod Security rules in the server.
I've disabled Mod Security by setting SecRuleEngine Off
in modesecurity.conf
, though it is not a good solution. Please update if anyone knows how to do this without turning off this module.
QUESTION
How to get data point label using click in plotly
Asked 2022-Feb-14 at 19:11I would like to store the data point label whenever I click it in my plotly plot. The label is the name of the data point that appears in the first column of my data frame.
For example if I hover over a data point it will show me the x and y information as well as the data point name: x: TRUE y: 27 Name: cheeseburger
What I want is to store the label of that data point, 'cheeseburger' as a variable to use later.
I have tried using plotly_click and accessing the event_data but it returns x and y values and all I want is the data point name. This is my code:
1
2 library(shiny)
3 library(plotly)
4
5ui <- navbarPage(fluid = TRUE, id = "navbarID",
6 theme = shinytheme("superhero"),
7 tabsetPanel(type = "tabs",
8 tabPanel("File Upload",
9
10 # Sidebar layout with input and output definitions ----
11 sidebarLayout(
12
13 # Sidebar panel for inputs ----
14 sidebarPanel(
15
16 # Input: Select a file ----
17 fileInput("file1", "Choose CSV File",
18 multiple = FALSE,
19 accept = c("text/csv",
20 "text/comma-separated-values,text/plain",
21 ".csv")),
22
23 # Horizontal line ----
24 tags$hr(),
25
26 # Input: Checkbox if file has header ----
27 checkboxInput("header", "Header", TRUE),
28
29 # Input: Select separator ----
30 radioButtons("sep", "Separator",
31 choices = c(Comma = ",",
32 Semicolon = ";",
33 Tab = "\t"),
34 selected = ","),
35
36 # Input: Select quotes ----
37 radioButtons("quote", "Quote",
38 choices = c(None = "",
39 "Double Quote" = '"',
40 "Single Quote" = "'"),
41 selected = '"'),
42
43 # Horizontal line ----
44 tags$hr(),
45
46 # Input: Select number of rows to display ----
47 radioButtons("disp", "Display",
48 choices = c(Head = "head",
49 All = "all"),
50 selected = "head")
51
52 ),
53
54
55 mainPanel(
56
57 # Output: Data file ----
58 tableOutput("contents")
59
60 ),
61
62 )
63 ),
64 tabPanel("firstbox",
65 uiOutput("box"),
66
67),
68 tabPanel("facet_plots",
69 mainPanel(plotlyOutput("ind_plot"))
70 ) # Main panel for displaying outputs ----
71))
72
73
74# server ----
75# Define server logic to plot various variables against
76server <- function(input, output, session) {
77
78
79 my_data <- reactive({
80
81 inFile <- input$file1
82 req(inFile)
83
84 # when reading semicolon separated files,
85 # having a comma separator causes `read.csv` to error
86 tryCatch(
87 {
88 df_x <<- read.csv(inFile$datapath,
89 header = input$header,
90 sep = input$sep,
91 quote = input$quote)
92
93 },
94 error = function(e) {
95 # return a safeError if a parsing error occurs
96 stop(safeError(e))
97 }
98 )
99
100 if(input$disp == "head") {
101 return(head(df_x))
102 }
103 else {
104 return(df_x)
105 }
106
107 })
108
109 #server logic for file upload tab
110 output$contents <- renderTable({
111 my_data()
112
113 })
114
115
116
117 #server logic for boxplot tab
118 output$box <- renderUI({
119 tabPanel("first_box",
120 sidebarPanel(
121 selectInput("variable", "Name:", unique(qc$Action)),
122 sliderInput("quantile", "Quantile Range:",
123 min = 75, max = 95, value = c(85), step = 5),
124 br(),
125 br(),
126
127mainPanel(
128 h2("title", align = "center"),
129plotlyOutput("plot", height = '1000px', width = "100%")
130 )
131
132)
133
134 })
135
136
137 observeEvent(input$file1, {
138 req(df_x)
139 source("db_prep.R")
140
141
142 fn <- reactive(get(paste0("s_", input$quantile)))
143 output$plot <- renderPlotly(fn()(input$variable))
144}) # ^^^ note the reactive value goes fn()(var)
145
146
147
148
149 s_75 <- function(var) box_75(var)
150 s_80 <- function(var) box_80(var)
151 s_85 <- function(var) box_85(var)
152 s_90 <- function(var) box_90(var)
153 s_95 <- function(var) box_95(var)
154 m_p <- function(var) com_g(var)
155
156
157 #Below is that part I am running into trouble
158
159 #create reactive for subset plot on second tab
160 observeEvent(input$variable, {
161 s <- reactive({
162 event_data("plotly_click", source = 'sub_plot')
163 })
164
165
166 observeEvent(s(), {
167 updateTabsetPanel(session, inputId = "navbarID", selected = "facet_plots")
168 })
169
170 output$ind_plot <- renderPlotly({
171 req(s())
172
173 m_p(s()) # <-- problem here. I need to feed data point label as a string into this function to transform and render new sub plot.
174 })
175
176 })
177
178
ANSWER
Answered 2022-Feb-14 at 19:11Updated based on OP's comment that the label for each point is placed using geom_text(label())
and converted to plotly object
1
2 library(shiny)
3 library(plotly)
4
5ui <- navbarPage(fluid = TRUE, id = "navbarID",
6 theme = shinytheme("superhero"),
7 tabsetPanel(type = "tabs",
8 tabPanel("File Upload",
9
10 # Sidebar layout with input and output definitions ----
11 sidebarLayout(
12
13 # Sidebar panel for inputs ----
14 sidebarPanel(
15
16 # Input: Select a file ----
17 fileInput("file1", "Choose CSV File",
18 multiple = FALSE,
19 accept = c("text/csv",
20 "text/comma-separated-values,text/plain",
21 ".csv")),
22
23 # Horizontal line ----
24 tags$hr(),
25
26 # Input: Checkbox if file has header ----
27 checkboxInput("header", "Header", TRUE),
28
29 # Input: Select separator ----
30 radioButtons("sep", "Separator",
31 choices = c(Comma = ",",
32 Semicolon = ";",
33 Tab = "\t"),
34 selected = ","),
35
36 # Input: Select quotes ----
37 radioButtons("quote", "Quote",
38 choices = c(None = "",
39 "Double Quote" = '"',
40 "Single Quote" = "'"),
41 selected = '"'),
42
43 # Horizontal line ----
44 tags$hr(),
45
46 # Input: Select number of rows to display ----
47 radioButtons("disp", "Display",
48 choices = c(Head = "head",
49 All = "all"),
50 selected = "head")
51
52 ),
53
54
55 mainPanel(
56
57 # Output: Data file ----
58 tableOutput("contents")
59
60 ),
61
62 )
63 ),
64 tabPanel("firstbox",
65 uiOutput("box"),
66
67),
68 tabPanel("facet_plots",
69 mainPanel(plotlyOutput("ind_plot"))
70 ) # Main panel for displaying outputs ----
71))
72
73
74# server ----
75# Define server logic to plot various variables against
76server <- function(input, output, session) {
77
78
79 my_data <- reactive({
80
81 inFile <- input$file1
82 req(inFile)
83
84 # when reading semicolon separated files,
85 # having a comma separator causes `read.csv` to error
86 tryCatch(
87 {
88 df_x <<- read.csv(inFile$datapath,
89 header = input$header,
90 sep = input$sep,
91 quote = input$quote)
92
93 },
94 error = function(e) {
95 # return a safeError if a parsing error occurs
96 stop(safeError(e))
97 }
98 )
99
100 if(input$disp == "head") {
101 return(head(df_x))
102 }
103 else {
104 return(df_x)
105 }
106
107 })
108
109 #server logic for file upload tab
110 output$contents <- renderTable({
111 my_data()
112
113 })
114
115
116
117 #server logic for boxplot tab
118 output$box <- renderUI({
119 tabPanel("first_box",
120 sidebarPanel(
121 selectInput("variable", "Name:", unique(qc$Action)),
122 sliderInput("quantile", "Quantile Range:",
123 min = 75, max = 95, value = c(85), step = 5),
124 br(),
125 br(),
126
127mainPanel(
128 h2("title", align = "center"),
129plotlyOutput("plot", height = '1000px', width = "100%")
130 )
131
132)
133
134 })
135
136
137 observeEvent(input$file1, {
138 req(df_x)
139 source("db_prep.R")
140
141
142 fn <- reactive(get(paste0("s_", input$quantile)))
143 output$plot <- renderPlotly(fn()(input$variable))
144}) # ^^^ note the reactive value goes fn()(var)
145
146
147
148
149 s_75 <- function(var) box_75(var)
150 s_80 <- function(var) box_80(var)
151 s_85 <- function(var) box_85(var)
152 s_90 <- function(var) box_90(var)
153 s_95 <- function(var) box_95(var)
154 m_p <- function(var) com_g(var)
155
156
157 #Below is that part I am running into trouble
158
159 #create reactive for subset plot on second tab
160 observeEvent(input$variable, {
161 s <- reactive({
162 event_data("plotly_click", source = 'sub_plot')
163 })
164
165
166 observeEvent(s(), {
167 updateTabsetPanel(session, inputId = "navbarID", selected = "facet_plots")
168 })
169
170 output$ind_plot <- renderPlotly({
171 req(s())
172
173 m_p(s()) # <-- problem here. I need to feed data point label as a string into this function to transform and render new sub plot.
174 })
175
176 })
177
178library(shiny)
179library(plotly)
180library(data.table)
181
182data = data.table(x=1:10, y=sample(1:100, 10))
183food_labels = sample(c("cheeseburger", "hamburger", "salad", "fries"), 10, replace=T)
184
185get_plotly <- function() {
186 ggplotly(ggplot(data,aes(x,y)) + geom_point() + geom_text(label=food_labels))
187}
188
189ui <- fluidPage(
190 plotlyOutput("plot"),
191 verbatimTextOutput(outputId = "clicked_point")
192)
193
194server <- function(input, output, session) {
195
196 plt <- reactive(get_plotly())
197
198 output$plot <- renderPlotly(plt())
199
200 s <- reactive(event_data("plotly_click"))
201
202 label_name <- eventReactive(s(), {
203 data.table(
204 x = plt()$x$data[[2]]$x,
205 y = plt()$x$data[[2]]$y,
206 text = plt()$x$data[[2]]$text
207 )[x==s()$x & y==s()$y, text]
208 })
209
210 output$clicked_point = renderPrint(label_name())
211}
212
213shinyApp(ui, server)
214
QUESTION
How to upload a stream to S3 with AWS SDK v3
Asked 2022-Feb-12 at 01:22I have to transfer a file from and API endpoint to two different bucket. The original upload is made using:
1curl -X PUT -F "data=@sample" "http://localhost:3000/upload/1/1"
2
The endpoint where the file is uploaded:
1curl -X PUT -F "data=@sample" "http://localhost:3000/upload/1/1"
2const PassThrough = require('stream').PassThrough;
3
4async function uploadFile (req, res) {
5 try {
6 const firstS3Stream = new PassThrough();
7 const secondS3Stream = new PassThrough();
8 req.pipe(firstS3Stream);
9 req.pipe(secondS3Stream);
10
11 await Promise.all([
12 uploadToFirstS3(firstS3Stream),
13 uploadToSecondS3(secondS3Stream),
14 ]);
15 return res.end();
16 } catch (err) {
17 console.log(err)
18 return res.status(500).send({ error: 'Unexpected error during file upload' });
19 }
20}
21
As you can see, I use two PassThrough streams, in order to duplicate the request stream into two readable streams, as suggested in this SO thread.
This piece of code remains unchanged, what is interesting here are the uploadToFirstS3
and uploadToSecondS3
functions. In this minimal example both do exactly the same thing with a different configuration, i will expend only one here.
What Works Well:
1curl -X PUT -F "data=@sample" "http://localhost:3000/upload/1/1"
2const PassThrough = require('stream').PassThrough;
3
4async function uploadFile (req, res) {
5 try {
6 const firstS3Stream = new PassThrough();
7 const secondS3Stream = new PassThrough();
8 req.pipe(firstS3Stream);
9 req.pipe(secondS3Stream);
10
11 await Promise.all([
12 uploadToFirstS3(firstS3Stream),
13 uploadToSecondS3(secondS3Stream),
14 ]);
15 return res.end();
16 } catch (err) {
17 console.log(err)
18 return res.status(500).send({ error: 'Unexpected error during file upload' });
19 }
20}
21const aws = require('aws-sdk');
22
23const s3 = new aws.S3({
24 accessKeyId: S3_API_KEY,
25 secretAccessKey: S3_API_SECRET,
26 region: S3_REGION,
27 signatureVersion: 'v4',
28});
29
30const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
31 const uploadParams = {
32 Bucket: S3_BUCKET_NAME,
33 Key: 'some-key',
34 Body: stream,
35 };
36 s3.upload(uploadParams, (err) => {
37 if (err) reject(err);
38 resolve(true);
39 });
40}));
41
This piece of code (based on the aws-sdk package) works fine. My issue here is that i want it to run with the @aws-sdk/client-s3 package in order to reduce the size of the project.
What doesn't work:
I first tried to use S3Client.send(PutObjectCommand):
1curl -X PUT -F "data=@sample" "http://localhost:3000/upload/1/1"
2const PassThrough = require('stream').PassThrough;
3
4async function uploadFile (req, res) {
5 try {
6 const firstS3Stream = new PassThrough();
7 const secondS3Stream = new PassThrough();
8 req.pipe(firstS3Stream);
9 req.pipe(secondS3Stream);
10
11 await Promise.all([
12 uploadToFirstS3(firstS3Stream),
13 uploadToSecondS3(secondS3Stream),
14 ]);
15 return res.end();
16 } catch (err) {
17 console.log(err)
18 return res.status(500).send({ error: 'Unexpected error during file upload' });
19 }
20}
21const aws = require('aws-sdk');
22
23const s3 = new aws.S3({
24 accessKeyId: S3_API_KEY,
25 secretAccessKey: S3_API_SECRET,
26 region: S3_REGION,
27 signatureVersion: 'v4',
28});
29
30const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
31 const uploadParams = {
32 Bucket: S3_BUCKET_NAME,
33 Key: 'some-key',
34 Body: stream,
35 };
36 s3.upload(uploadParams, (err) => {
37 if (err) reject(err);
38 resolve(true);
39 });
40}));
41const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
42
43const s3 = new S3Client({
44 credentials: {
45 accessKeyId: S3_API_KEY,
46 secretAccessKey: S3_API_SECRET,
47 },
48 region: S3_REGION,
49 signatureVersion: 'v4',
50});
51
52const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
53 const uploadParams = {
54 Bucket: S3_BUCKET_NAME,
55 Key:'some-key',
56 Body: stream,
57 };
58 s3.send(new PutObjectCommand(uploadParams), (err) => {
59 if (err) reject(err);
60 resolve(true);
61 });
62}));
63
Then I tried S3.putObject(PutObjectCommandInput):
1curl -X PUT -F "data=@sample" "http://localhost:3000/upload/1/1"
2const PassThrough = require('stream').PassThrough;
3
4async function uploadFile (req, res) {
5 try {
6 const firstS3Stream = new PassThrough();
7 const secondS3Stream = new PassThrough();
8 req.pipe(firstS3Stream);
9 req.pipe(secondS3Stream);
10
11 await Promise.all([
12 uploadToFirstS3(firstS3Stream),
13 uploadToSecondS3(secondS3Stream),
14 ]);
15 return res.end();
16 } catch (err) {
17 console.log(err)
18 return res.status(500).send({ error: 'Unexpected error during file upload' });
19 }
20}
21const aws = require('aws-sdk');
22
23const s3 = new aws.S3({
24 accessKeyId: S3_API_KEY,
25 secretAccessKey: S3_API_SECRET,
26 region: S3_REGION,
27 signatureVersion: 'v4',
28});
29
30const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
31 const uploadParams = {
32 Bucket: S3_BUCKET_NAME,
33 Key: 'some-key',
34 Body: stream,
35 };
36 s3.upload(uploadParams, (err) => {
37 if (err) reject(err);
38 resolve(true);
39 });
40}));
41const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
42
43const s3 = new S3Client({
44 credentials: {
45 accessKeyId: S3_API_KEY,
46 secretAccessKey: S3_API_SECRET,
47 },
48 region: S3_REGION,
49 signatureVersion: 'v4',
50});
51
52const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
53 const uploadParams = {
54 Bucket: S3_BUCKET_NAME,
55 Key:'some-key',
56 Body: stream,
57 };
58 s3.send(new PutObjectCommand(uploadParams), (err) => {
59 if (err) reject(err);
60 resolve(true);
61 });
62}));
63const { S3 } = require('@aws-sdk/client-s3');
64
65const s3 = new S3({
66 credentials: {
67 accessKeyId: S3_API_KEY,
68 secretAccessKey: S3_API_SECRET,
69 },
70 region: S3_REGION,
71 signatureVersion: 'v4',
72});
73
74const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
75 const uploadParams = {
76 Bucket: S3_BUCKET_NAME,
77 Key:'some-key',
78 Body: stream,
79 };
80 s3.putObject(uploadParams, (err) => {
81 if (err) reject(err);
82 resolve(true);
83 });
84}));
85
The two last examples both give me a 501 - Not Implemented error with the header Transfer-Encoding
. I checked req.headers
and there is no Transfer-Encoding
in it, so I guess the sdk adds in the request to s3 ?
Since the first example (based on aws-sdk) works fine, I'm sure the error is not due to an empty body in the request as suggested in this SO thread.
Still, I thought maybe the stream wasn't readable yet when triggering the upload, thus I wrapped the calls to uploadToFirstS3
and uploadToSecondS3
with a callback triggered by the req.on('readable', callback)
event, but nothing changed.
I would like to process the files in memory without storing it on the disk at any time. Is there a way to achieve it using the @aws-sdk/client-s3 package ?
ANSWER
Answered 2022-Feb-12 at 01:22In S3 you can use the Upload
class from @aws-sdk/lib-storage
to do multipart uploads. Seems like there might be no mention of this in the docs site for @aws-sdk/client-s3
unfortunately.
It's mentioned in the upgrade guide here: https://github.com/aws/aws-sdk-js-v3/blob/main/UPGRADING.md#s3-multipart-upload
Here's the example provided in https://github.com/aws/aws-sdk-js-v3/tree/main/lib/lib-storage:
1curl -X PUT -F "data=@sample" "http://localhost:3000/upload/1/1"
2const PassThrough = require('stream').PassThrough;
3
4async function uploadFile (req, res) {
5 try {
6 const firstS3Stream = new PassThrough();
7 const secondS3Stream = new PassThrough();
8 req.pipe(firstS3Stream);
9 req.pipe(secondS3Stream);
10
11 await Promise.all([
12 uploadToFirstS3(firstS3Stream),
13 uploadToSecondS3(secondS3Stream),
14 ]);
15 return res.end();
16 } catch (err) {
17 console.log(err)
18 return res.status(500).send({ error: 'Unexpected error during file upload' });
19 }
20}
21const aws = require('aws-sdk');
22
23const s3 = new aws.S3({
24 accessKeyId: S3_API_KEY,
25 secretAccessKey: S3_API_SECRET,
26 region: S3_REGION,
27 signatureVersion: 'v4',
28});
29
30const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
31 const uploadParams = {
32 Bucket: S3_BUCKET_NAME,
33 Key: 'some-key',
34 Body: stream,
35 };
36 s3.upload(uploadParams, (err) => {
37 if (err) reject(err);
38 resolve(true);
39 });
40}));
41const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
42
43const s3 = new S3Client({
44 credentials: {
45 accessKeyId: S3_API_KEY,
46 secretAccessKey: S3_API_SECRET,
47 },
48 region: S3_REGION,
49 signatureVersion: 'v4',
50});
51
52const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
53 const uploadParams = {
54 Bucket: S3_BUCKET_NAME,
55 Key:'some-key',
56 Body: stream,
57 };
58 s3.send(new PutObjectCommand(uploadParams), (err) => {
59 if (err) reject(err);
60 resolve(true);
61 });
62}));
63const { S3 } = require('@aws-sdk/client-s3');
64
65const s3 = new S3({
66 credentials: {
67 accessKeyId: S3_API_KEY,
68 secretAccessKey: S3_API_SECRET,
69 },
70 region: S3_REGION,
71 signatureVersion: 'v4',
72});
73
74const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
75 const uploadParams = {
76 Bucket: S3_BUCKET_NAME,
77 Key:'some-key',
78 Body: stream,
79 };
80 s3.putObject(uploadParams, (err) => {
81 if (err) reject(err);
82 resolve(true);
83 });
84}));
85 import { Upload } from "@aws-sdk/lib-storage";
86 import { S3Client } from "@aws-sdk/client-s3";
87
88 const target = { Bucket, Key, Body };
89 try {
90 const parallelUploads3 = new Upload({
91 client: new S3Client({}),
92 tags: [...], // optional tags
93 queueSize: 4, // optional concurrency configuration
94 leavePartsOnError: false, // optional manually handle dropped parts
95 params: target,
96 });
97
98 parallelUploads3.on("httpUploadProgress", (progress) => {
99 console.log(progress);
100 });
101
102 await parallelUploads3.done();
103 } catch (e) {
104 console.log(e);
105 }
106
QUESTION
Spring Boot 2.5.x: Required request part 'file' is not present
Asked 2022-Jan-17 at 08:14I have a file uploading api which was working perfectly fine under the spring boot
version 2.1.13
. After upgrading the version to 2.5.2
, it started to throw an exception. Looking at the changelogs, I couldn't see anything significant changes that's related to Multipart
processing. What could I be missing here? Below are the sample codes I have.
Exception
1org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
2 at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:161) ~[spring-webmvc-5.3.8.jar:5.3.8]
3 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.3.8.jar:5.3.8]
4 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170) ~[spring-web-5.3.8.jar:5.3.8]
5 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-5.3.8.jar:5.3.8]
6 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.8.jar:5.3.8]
7 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.8.jar:5.3.8]
8 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.8.jar:5.3.8]
9 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.8.jar:5.3.8]
10 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.8.jar:5.3.8]
11 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.8.jar:5.3.8]
12 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.8.jar:5.3.8]
13 at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.8.jar:5.3.8]
14 at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [tomcat-embed-core-9.0.48.jar:4.0.FR]
15
application.properties
1org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
2 at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:161) ~[spring-webmvc-5.3.8.jar:5.3.8]
3 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.3.8.jar:5.3.8]
4 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170) ~[spring-web-5.3.8.jar:5.3.8]
5 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-5.3.8.jar:5.3.8]
6 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.8.jar:5.3.8]
7 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.8.jar:5.3.8]
8 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.8.jar:5.3.8]
9 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.8.jar:5.3.8]
10 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.8.jar:5.3.8]
11 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.8.jar:5.3.8]
12 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.8.jar:5.3.8]
13 at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.8.jar:5.3.8]
14 at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [tomcat-embed-core-9.0.48.jar:4.0.FR]
15spring.servlet.multipart.enabled=true
16spring.servlet.multipart.max-file-size=20MB
17spring.servlet.multipart.max-request-size=20MB
18
controller end point
1org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
2 at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:161) ~[spring-webmvc-5.3.8.jar:5.3.8]
3 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.3.8.jar:5.3.8]
4 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170) ~[spring-web-5.3.8.jar:5.3.8]
5 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-5.3.8.jar:5.3.8]
6 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.8.jar:5.3.8]
7 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.8.jar:5.3.8]
8 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.8.jar:5.3.8]
9 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.8.jar:5.3.8]
10 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.8.jar:5.3.8]
11 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.8.jar:5.3.8]
12 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.8.jar:5.3.8]
13 at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.8.jar:5.3.8]
14 at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [tomcat-embed-core-9.0.48.jar:4.0.FR]
15spring.servlet.multipart.enabled=true
16spring.servlet.multipart.max-file-size=20MB
17spring.servlet.multipart.max-request-size=20MB
18@PostMapping(
19 value = "/upload",
20 consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
21 produces = MediaType.APPLICATION_JSON_VALUE
22)
23public ResponseEntity<Object> uploadFile(@RequestPart("file") MultipartFile file) {
24...
25}
26
Request Payload Sample
1org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
2 at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:161) ~[spring-webmvc-5.3.8.jar:5.3.8]
3 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.3.8.jar:5.3.8]
4 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170) ~[spring-web-5.3.8.jar:5.3.8]
5 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-5.3.8.jar:5.3.8]
6 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.8.jar:5.3.8]
7 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.8.jar:5.3.8]
8 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.8.jar:5.3.8]
9 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.8.jar:5.3.8]
10 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.8.jar:5.3.8]
11 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.8.jar:5.3.8]
12 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.8.jar:5.3.8]
13 at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.8.jar:5.3.8]
14 at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [tomcat-embed-core-9.0.48.jar:4.0.FR]
15spring.servlet.multipart.enabled=true
16spring.servlet.multipart.max-file-size=20MB
17spring.servlet.multipart.max-request-size=20MB
18@PostMapping(
19 value = "/upload",
20 consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
21 produces = MediaType.APPLICATION_JSON_VALUE
22)
23public ResponseEntity<Object> uploadFile(@RequestPart("file") MultipartFile file) {
24...
25}
26POST http://localhost:8080/upload
27Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGG9dgUb5THDV0eDB
28
29------WebKitFormBoundaryGG9dgUb5THDV0eDB
30Content-Disposition: form-data; name="file"; filename="Sample.pdf"
31Content-Type: application/pdf
32
33------WebKitFormBoundaryGG9dgUb5THDV0eDB--
34
Note: I don't have any MultipartResolver
bean defined in my configuration. I tried adding the MultipartResolver bean definition as follows (only one at a time) but didn't seem to resolve the issue.
1org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
2 at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:161) ~[spring-webmvc-5.3.8.jar:5.3.8]
3 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.3.8.jar:5.3.8]
4 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170) ~[spring-web-5.3.8.jar:5.3.8]
5 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-5.3.8.jar:5.3.8]
6 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.8.jar:5.3.8]
7 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.8.jar:5.3.8]
8 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.8.jar:5.3.8]
9 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.8.jar:5.3.8]
10 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.8.jar:5.3.8]
11 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.8.jar:5.3.8]
12 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.8.jar:5.3.8]
13 at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.8.jar:5.3.8]
14 at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [tomcat-embed-core-9.0.48.jar:4.0.FR]
15spring.servlet.multipart.enabled=true
16spring.servlet.multipart.max-file-size=20MB
17spring.servlet.multipart.max-request-size=20MB
18@PostMapping(
19 value = "/upload",
20 consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
21 produces = MediaType.APPLICATION_JSON_VALUE
22)
23public ResponseEntity<Object> uploadFile(@RequestPart("file") MultipartFile file) {
24...
25}
26POST http://localhost:8080/upload
27Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGG9dgUb5THDV0eDB
28
29------WebKitFormBoundaryGG9dgUb5THDV0eDB
30Content-Disposition: form-data; name="file"; filename="Sample.pdf"
31Content-Type: application/pdf
32
33------WebKitFormBoundaryGG9dgUb5THDV0eDB--
34@Bean
35public CommonsMultipartResolver multipartResolver() { // didn't work
36 return new CommonsMultipartResolver();
37}
38
39@Bean
40public StandardServletMultipartResolver multipartResolver() { // didn't work
41 return new StandardServletMultipartResolver();
42}
43
ANSWER
Answered 2021-Aug-17 at 17:03It turns out this issue was affected after the Spring Boot 2.2
. Since that version, the filter HttpHiddenMethodFilter
was disabled by default. The issue got fixed after enabling the filter in application.properties
.
1org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
2 at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:161) ~[spring-webmvc-5.3.8.jar:5.3.8]
3 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.3.8.jar:5.3.8]
4 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170) ~[spring-web-5.3.8.jar:5.3.8]
5 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-5.3.8.jar:5.3.8]
6 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.8.jar:5.3.8]
7 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.8.jar:5.3.8]
8 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.8.jar:5.3.8]
9 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.8.jar:5.3.8]
10 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.8.jar:5.3.8]
11 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.8.jar:5.3.8]
12 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.8.jar:5.3.8]
13 at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.8.jar:5.3.8]
14 at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [tomcat-embed-core-9.0.48.jar:4.0.FR]
15spring.servlet.multipart.enabled=true
16spring.servlet.multipart.max-file-size=20MB
17spring.servlet.multipart.max-request-size=20MB
18@PostMapping(
19 value = "/upload",
20 consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
21 produces = MediaType.APPLICATION_JSON_VALUE
22)
23public ResponseEntity<Object> uploadFile(@RequestPart("file") MultipartFile file) {
24...
25}
26POST http://localhost:8080/upload
27Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGG9dgUb5THDV0eDB
28
29------WebKitFormBoundaryGG9dgUb5THDV0eDB
30Content-Disposition: form-data; name="file"; filename="Sample.pdf"
31Content-Type: application/pdf
32
33------WebKitFormBoundaryGG9dgUb5THDV0eDB--
34@Bean
35public CommonsMultipartResolver multipartResolver() { // didn't work
36 return new CommonsMultipartResolver();
37}
38
39@Bean
40public StandardServletMultipartResolver multipartResolver() { // didn't work
41 return new StandardServletMultipartResolver();
42}
43spring.mvc.hiddenmethod.filter.enabled=true
44
My Findings in Detail
The purpose of the above filter has nothing to do with the error I was getting. But the request parts
was getting initialized as a side effect of executing the filter. More specifically, when the filter tries to retrieve the _method
parameter value (e.g. request.getParameter("_method")
, the getParameter
method of the request
instance internally seems to parse the parameters which then initializes the request parts
. So when the filter was disabled in spring-boot
version 2.2, there was nothing to initialize the request parts
.
I feel like the request parts
initialization should be fixed within the Spring
framework itself. But until then, either we could enable the HttpHiddenMethodFilter
filter, or we could define a custom filter that takes care of initializing the request parts
, something like below:
1org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
2 at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:161) ~[spring-webmvc-5.3.8.jar:5.3.8]
3 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.3.8.jar:5.3.8]
4 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170) ~[spring-web-5.3.8.jar:5.3.8]
5 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-5.3.8.jar:5.3.8]
6 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.8.jar:5.3.8]
7 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.8.jar:5.3.8]
8 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.8.jar:5.3.8]
9 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.8.jar:5.3.8]
10 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.8.jar:5.3.8]
11 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.8.jar:5.3.8]
12 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.8.jar:5.3.8]
13 at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.8.jar:5.3.8]
14 at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [tomcat-embed-core-9.0.48.jar:4.0.FR]
15spring.servlet.multipart.enabled=true
16spring.servlet.multipart.max-file-size=20MB
17spring.servlet.multipart.max-request-size=20MB
18@PostMapping(
19 value = "/upload",
20 consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
21 produces = MediaType.APPLICATION_JSON_VALUE
22)
23public ResponseEntity<Object> uploadFile(@RequestPart("file") MultipartFile file) {
24...
25}
26POST http://localhost:8080/upload
27Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGG9dgUb5THDV0eDB
28
29------WebKitFormBoundaryGG9dgUb5THDV0eDB
30Content-Disposition: form-data; name="file"; filename="Sample.pdf"
31Content-Type: application/pdf
32
33------WebKitFormBoundaryGG9dgUb5THDV0eDB--
34@Bean
35public CommonsMultipartResolver multipartResolver() { // didn't work
36 return new CommonsMultipartResolver();
37}
38
39@Bean
40public StandardServletMultipartResolver multipartResolver() { // didn't work
41 return new StandardServletMultipartResolver();
42}
43spring.mvc.hiddenmethod.filter.enabled=true
44@Configuration
45@Order(Ordered.HIGHEST_PRECEDENCE)
46public class RequestInitializerFilter extends OncePerRequestFilter {
47
48 @Override
49 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
50
51 request.getParameterNames(); // this takes care of initializing request `parts`
52
53 filterChain.doFilter(request, response);
54 }
55}
56
QUESTION
How to get a upload button in swagger for IFormFile combined with other properties?
Asked 2022-Jan-12 at 02:53I have created a Asp.net core 3.1 web api with Swagger to upload files to server. the following code is working fine:
1 [HttpPost("PostFile")]
2 public ActionResult PostFile(IFormFile uploadedFile)
3 {
4 var saveFilePath = Path.Combine("c:\\savefilepath\\", uploadedFile.FileName);
5 using (var stream = new FileStream(saveFilePath, FileMode.Create))
6 {
7 uploadedFile.CopyToAsync(stream);
8 }
9 return Ok();
10 }
11
I get a nice upload button in swagger when I try to run this.
However, now I wanted to use a different model. that has some more properties along with the IFormFile.
1 [HttpPost("PostFile")]
2 public ActionResult PostFile(IFormFile uploadedFile)
3 {
4 var saveFilePath = Path.Combine("c:\\savefilepath\\", uploadedFile.FileName);
5 using (var stream = new FileStream(saveFilePath, FileMode.Create))
6 {
7 uploadedFile.CopyToAsync(stream);
8 }
9 return Ok();
10 }
11public class FileUploadRequest
12{
13 public string UploaderName { get; set; }
14 public string UploaderAddress { get; set; }
15 public IFormFile File { get; set; }
16}
17
When I try to use this model, I dont see any upload button in Swagger that will help me to attach the file in the request.
For some reason, it shows the IFormFile as String. How can I get a upload button here?
ANSWER
Answered 2022-Jan-12 at 02:53In ASP.NET Core Web API, it binds application/json
format data by default. But what your model need is multipart/form-data
type data. So you need [FromForm]
attribute to specific the source.
I use Swashbuckle.AspNetCore
version 5.6.3 in ASP.NET Core 3.1:
1 [HttpPost("PostFile")]
2 public ActionResult PostFile(IFormFile uploadedFile)
3 {
4 var saveFilePath = Path.Combine("c:\\savefilepath\\", uploadedFile.FileName);
5 using (var stream = new FileStream(saveFilePath, FileMode.Create))
6 {
7 uploadedFile.CopyToAsync(stream);
8 }
9 return Ok();
10 }
11public class FileUploadRequest
12{
13 public string UploaderName { get; set; }
14 public string UploaderAddress { get; set; }
15 public IFormFile File { get; set; }
16}
17[HttpPost]
18public ActionResult PostFile([FromForm]FileUploadRequest model)
19{
20
21}
22
QUESTION
Problem dealing with a space when moving JSON to Python
Asked 2022-Jan-04 at 23:11I am high school math teacher who is teaching myself programming. My apologies in advance if I don't phrase some of this correctly.
I am collecting CSV data from the user and trying to move it to a SQLite database via Python.
Everything works fine unless one of the values has a space in it.
For example, here is part of my JavaScript object:
1Firstname: "Bruce"
2Grade: ""
3Lastname: "Wayne Jr"
4Nickname: ""
5
Here is the corresponding piece after applying JSON.stringify
:
{"Firstname":"Bruce","Lastname":"Wayne Jr","Nickname":"","Grade":""}
This is then passed to Python via a form. In Python, I use:
1Firstname: "Bruce"
2Grade: ""
3Lastname: "Wayne Jr"
4Nickname: ""
5data = request.form.get("data")
6print(data)
7data2 = json.loads(data)
8print(data2)
9
I get a bunch of error messages, ending with: json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 250 (char 249)
and the log of the first print gives:
1Firstname: "Bruce"
2Grade: ""
3Lastname: "Wayne Jr"
4Nickname: ""
5data = request.form.get("data")
6print(data)
7data2 = json.loads(data)
8print(data2)
9[{"Firstname":"Jason","Lastname":"Bourne","Nickname":"","Grade":"10"},
10 {"Firstname":"Steve","Lastname":"McGarret","Nickname":"5-0","Grade":""},
11 {"Firstname":"Danny","Lastname":"Williams","Nickname":"Dano","Grade":"12"},
12 {"Firstname":"Bruce","Lastname":"Wayne
13
So it seems to break on the space in "Wayne Jr"
.
I used what I learned here to build the basics:
https://bl.ocks.org/HarryStevens/0ce529b9b5e4ea17f8db25324423818f
I believe this JavaScript function is parsing the user data:
1Firstname: "Bruce"
2Grade: ""
3Lastname: "Wayne Jr"
4Nickname: ""
5data = request.form.get("data")
6print(data)
7data2 = json.loads(data)
8print(data2)
9[{"Firstname":"Jason","Lastname":"Bourne","Nickname":"","Grade":"10"},
10 {"Firstname":"Steve","Lastname":"McGarret","Nickname":"5-0","Grade":""},
11 {"Firstname":"Danny","Lastname":"Williams","Nickname":"Dano","Grade":"12"},
12 {"Firstname":"Bruce","Lastname":"Wayne
13function changeDataFromField(cb){
14 var arr = [];
15 $('#enter-data-field').val().replace( /\n/g, "^^^xyz" ).split( "^^^xyz" ).forEach(function(d){
16 arr.push(d.replace( /\t/g, "^^^xyz" ).split( "^^^xyz" ))
17 });
18 cb(csvToJson(arr));
19 }
20
Updates based on comments:
I am using a POST request. No AJAX.
There are actually 2 inputs for the user. A text box where they can paste CSV data and a file upload option. Here is some more of the JavaScript.
1Firstname: "Bruce"
2Grade: ""
3Lastname: "Wayne Jr"
4Nickname: ""
5data = request.form.get("data")
6print(data)
7data2 = json.loads(data)
8print(data2)
9[{"Firstname":"Jason","Lastname":"Bourne","Nickname":"","Grade":"10"},
10 {"Firstname":"Steve","Lastname":"McGarret","Nickname":"5-0","Grade":""},
11 {"Firstname":"Danny","Lastname":"Williams","Nickname":"Dano","Grade":"12"},
12 {"Firstname":"Bruce","Lastname":"Wayne
13function changeDataFromField(cb){
14 var arr = [];
15 $('#enter-data-field').val().replace( /\n/g, "^^^xyz" ).split( "^^^xyz" ).forEach(function(d){
16 arr.push(d.replace( /\t/g, "^^^xyz" ).split( "^^^xyz" ))
17 });
18 cb(csvToJson(arr));
19 }
20// Use the HTML5 File API to read the CSV
21 function changeDataFromUpload(evt, cb){
22 if (!browserSupportFileUpload()) {
23 console.error("The File APIs are not fully supported in this browser!");
24 } else {
25 var data = null;
26 var file = evt.target.files[0];
27 var fileName = file.name;
28 $("#filename").html(fileName);
29
30 if (file !== "") {
31 var reader = new FileReader();
32
33 reader.onload = function(event) {
34 var csvData = event.target.result;
35 var parsed = Papa.parse(csvData);
36 cb(csvToJson(parsed.data));
37 };
38 reader.onerror = function() {
39 console.error("Unable to read " + file.fileName);
40 };
41 }
42
43 reader.readAsText(file);
44 $("#update-data-from-file")[0].value = "";
45 }
46 }
47
48 // Method that checks that the browser supports the HTML5 File API
49 function browserSupportFileUpload() {
50 var isCompatible = false;
51 if (window.File && window.FileReader && window.FileList && window.Blob) {
52 isCompatible = true;
53 }
54 return isCompatible;
55 }
56
57 // Parse the CSV input into JSON
58 function csvToJson(data) {
59 var cols = ["Firstname","Lastname","Nickname","Grade"];
60 var out = [];
61 for (var i = 0; i < data.length; i++){
62 var obj = {};
63 var row = data[i];
64 cols.forEach(function(col, index){
65 if (row[index]) {
66 obj[col] = row[index];
67 }
68 else {
69 obj[col] = "";
70 }
71 });
72 out.push(obj);
73 }
74 return out;
75 }
76
77 // Produces table for user to check appearance of data and button to complete upload
78 function makeTable(data) {
79 console.log(data);
80 send_data = JSON.stringify(data);
81 console.log(send_data);
82 var table_data = '<table style="table-layout: fixed; width: 100%" class="table table-striped">';
83 table_data += '<th>First name</th><th>Last name</th><th>Nickname</th><th>Grade</th>'
84 for(var count = 0; count < data.length; count++) {
85 table_data += '<tr>';
86 table_data += '<td>'+data[count]['Firstname']+'</td>';
87 table_data += '<td>'+data[count]['Lastname']+'</td>';
88 table_data += '<td>'+data[count]['Nickname']+'</td>';
89 table_data += '<td>'+data[count]['Grade']+'</td>';
90 table_data += '</tr>';
91 }
92 table_data += '</table>';
93 table_data += '<p><form action="/uploaded" method="post">';
94 table_data += 'Does the data look OK? If so, click to upload. ';
95 table_data += '<button class="btn btn-primary" type="submit">Upload</button><p>';
96 table_data += '<input type="hidden" id="data" name="data" value='+send_data+'>';
97 table_data += '<input type="hidden" name="class_id" value="{{ class_id }}">';
98 table_data += '</form>';
99 table_data += 'Otherwise, fix the file and reload.';
100 document.getElementById("result_table").innerHTML = table_data;
101 }
102 </script>
103
ANSWER
Answered 2022-Jan-03 at 04:51The JavaScript can be made a lot simpler. If you do the following instead, do you have any problems with the JSON getting cut off?
1Firstname: "Bruce"
2Grade: ""
3Lastname: "Wayne Jr"
4Nickname: ""
5data = request.form.get("data")
6print(data)
7data2 = json.loads(data)
8print(data2)
9[{"Firstname":"Jason","Lastname":"Bourne","Nickname":"","Grade":"10"},
10 {"Firstname":"Steve","Lastname":"McGarret","Nickname":"5-0","Grade":""},
11 {"Firstname":"Danny","Lastname":"Williams","Nickname":"Dano","Grade":"12"},
12 {"Firstname":"Bruce","Lastname":"Wayne
13function changeDataFromField(cb){
14 var arr = [];
15 $('#enter-data-field').val().replace( /\n/g, "^^^xyz" ).split( "^^^xyz" ).forEach(function(d){
16 arr.push(d.replace( /\t/g, "^^^xyz" ).split( "^^^xyz" ))
17 });
18 cb(csvToJson(arr));
19 }
20// Use the HTML5 File API to read the CSV
21 function changeDataFromUpload(evt, cb){
22 if (!browserSupportFileUpload()) {
23 console.error("The File APIs are not fully supported in this browser!");
24 } else {
25 var data = null;
26 var file = evt.target.files[0];
27 var fileName = file.name;
28 $("#filename").html(fileName);
29
30 if (file !== "") {
31 var reader = new FileReader();
32
33 reader.onload = function(event) {
34 var csvData = event.target.result;
35 var parsed = Papa.parse(csvData);
36 cb(csvToJson(parsed.data));
37 };
38 reader.onerror = function() {
39 console.error("Unable to read " + file.fileName);
40 };
41 }
42
43 reader.readAsText(file);
44 $("#update-data-from-file")[0].value = "";
45 }
46 }
47
48 // Method that checks that the browser supports the HTML5 File API
49 function browserSupportFileUpload() {
50 var isCompatible = false;
51 if (window.File && window.FileReader && window.FileList && window.Blob) {
52 isCompatible = true;
53 }
54 return isCompatible;
55 }
56
57 // Parse the CSV input into JSON
58 function csvToJson(data) {
59 var cols = ["Firstname","Lastname","Nickname","Grade"];
60 var out = [];
61 for (var i = 0; i < data.length; i++){
62 var obj = {};
63 var row = data[i];
64 cols.forEach(function(col, index){
65 if (row[index]) {
66 obj[col] = row[index];
67 }
68 else {
69 obj[col] = "";
70 }
71 });
72 out.push(obj);
73 }
74 return out;
75 }
76
77 // Produces table for user to check appearance of data and button to complete upload
78 function makeTable(data) {
79 console.log(data);
80 send_data = JSON.stringify(data);
81 console.log(send_data);
82 var table_data = '<table style="table-layout: fixed; width: 100%" class="table table-striped">';
83 table_data += '<th>First name</th><th>Last name</th><th>Nickname</th><th>Grade</th>'
84 for(var count = 0; count < data.length; count++) {
85 table_data += '<tr>';
86 table_data += '<td>'+data[count]['Firstname']+'</td>';
87 table_data += '<td>'+data[count]['Lastname']+'</td>';
88 table_data += '<td>'+data[count]['Nickname']+'</td>';
89 table_data += '<td>'+data[count]['Grade']+'</td>';
90 table_data += '</tr>';
91 }
92 table_data += '</table>';
93 table_data += '<p><form action="/uploaded" method="post">';
94 table_data += 'Does the data look OK? If so, click to upload. ';
95 table_data += '<button class="btn btn-primary" type="submit">Upload</button><p>';
96 table_data += '<input type="hidden" id="data" name="data" value='+send_data+'>';
97 table_data += '<input type="hidden" name="class_id" value="{{ class_id }}">';
98 table_data += '</form>';
99 table_data += 'Otherwise, fix the file and reload.';
100 document.getElementById("result_table").innerHTML = table_data;
101 }
102 </script>
103document.getElementById('update-data-from-file').addEventListener('change', function(evt){
104 var file = evt.target.files[0];
105 document.getElementById('filename').innerText = file.name
106
107 if (file === "")
108 return;
109
110 Papa.parse(file, {
111 header: true,
112 skipEmptyLines: true,
113 complete: function(results) {
114 json = results.data
115 console.log(json)
116 // Do stuff with the json here
117 }
118 });
119
120 document.getElementById('update-data-from-file').value = ''
121})
1Firstname: "Bruce"
2Grade: ""
3Lastname: "Wayne Jr"
4Nickname: ""
5data = request.form.get("data")
6print(data)
7data2 = json.loads(data)
8print(data2)
9[{"Firstname":"Jason","Lastname":"Bourne","Nickname":"","Grade":"10"},
10 {"Firstname":"Steve","Lastname":"McGarret","Nickname":"5-0","Grade":""},
11 {"Firstname":"Danny","Lastname":"Williams","Nickname":"Dano","Grade":"12"},
12 {"Firstname":"Bruce","Lastname":"Wayne
13function changeDataFromField(cb){
14 var arr = [];
15 $('#enter-data-field').val().replace( /\n/g, "^^^xyz" ).split( "^^^xyz" ).forEach(function(d){
16 arr.push(d.replace( /\t/g, "^^^xyz" ).split( "^^^xyz" ))
17 });
18 cb(csvToJson(arr));
19 }
20// Use the HTML5 File API to read the CSV
21 function changeDataFromUpload(evt, cb){
22 if (!browserSupportFileUpload()) {
23 console.error("The File APIs are not fully supported in this browser!");
24 } else {
25 var data = null;
26 var file = evt.target.files[0];
27 var fileName = file.name;
28 $("#filename").html(fileName);
29
30 if (file !== "") {
31 var reader = new FileReader();
32
33 reader.onload = function(event) {
34 var csvData = event.target.result;
35 var parsed = Papa.parse(csvData);
36 cb(csvToJson(parsed.data));
37 };
38 reader.onerror = function() {
39 console.error("Unable to read " + file.fileName);
40 };
41 }
42
43 reader.readAsText(file);
44 $("#update-data-from-file")[0].value = "";
45 }
46 }
47
48 // Method that checks that the browser supports the HTML5 File API
49 function browserSupportFileUpload() {
50 var isCompatible = false;
51 if (window.File && window.FileReader && window.FileList && window.Blob) {
52 isCompatible = true;
53 }
54 return isCompatible;
55 }
56
57 // Parse the CSV input into JSON
58 function csvToJson(data) {
59 var cols = ["Firstname","Lastname","Nickname","Grade"];
60 var out = [];
61 for (var i = 0; i < data.length; i++){
62 var obj = {};
63 var row = data[i];
64 cols.forEach(function(col, index){
65 if (row[index]) {
66 obj[col] = row[index];
67 }
68 else {
69 obj[col] = "";
70 }
71 });
72 out.push(obj);
73 }
74 return out;
75 }
76
77 // Produces table for user to check appearance of data and button to complete upload
78 function makeTable(data) {
79 console.log(data);
80 send_data = JSON.stringify(data);
81 console.log(send_data);
82 var table_data = '<table style="table-layout: fixed; width: 100%" class="table table-striped">';
83 table_data += '<th>First name</th><th>Last name</th><th>Nickname</th><th>Grade</th>'
84 for(var count = 0; count < data.length; count++) {
85 table_data += '<tr>';
86 table_data += '<td>'+data[count]['Firstname']+'</td>';
87 table_data += '<td>'+data[count]['Lastname']+'</td>';
88 table_data += '<td>'+data[count]['Nickname']+'</td>';
89 table_data += '<td>'+data[count]['Grade']+'</td>';
90 table_data += '</tr>';
91 }
92 table_data += '</table>';
93 table_data += '<p><form action="/uploaded" method="post">';
94 table_data += 'Does the data look OK? If so, click to upload. ';
95 table_data += '<button class="btn btn-primary" type="submit">Upload</button><p>';
96 table_data += '<input type="hidden" id="data" name="data" value='+send_data+'>';
97 table_data += '<input type="hidden" name="class_id" value="{{ class_id }}">';
98 table_data += '</form>';
99 table_data += 'Otherwise, fix the file and reload.';
100 document.getElementById("result_table").innerHTML = table_data;
101 }
102 </script>
103document.getElementById('update-data-from-file').addEventListener('change', function(evt){
104 var file = evt.target.files[0];
105 document.getElementById('filename').innerText = file.name
106
107 if (file === "")
108 return;
109
110 Papa.parse(file, {
111 header: true,
112 skipEmptyLines: true,
113 complete: function(results) {
114 json = results.data
115 console.log(json)
116 // Do stuff with the json here
117 }
118 });
119
120 document.getElementById('update-data-from-file').value = ''
121})<!DOCTYPE html>
122<html>
123 <head>
124 <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.0.2/papaparse.min.js"></script>
125 </head>
126 <body>
127
128 <label>
129 Upload CSV
130 <input type="file" name="File Upload" id="update-data-from-file" accept=".csv" />
131 </label>
132 <div id="filename">No file chosen</div>
133
134 </body>
135</html>
QUESTION
Java can't upload file with @Pathvariable optional
Asked 2022-Jan-03 at 12:27I try to build a todoapp with the function to upload files. Now i want to can upload files on a task or simply upload files without tasks. For that i need the @PathVariable Annotation to be optional.
This is my Controller:
1@PostMapping("/upload/{taskId}")
2private ResponseEntity<String> uploadFile(@CurrentUser UserPrincipal userPrincipal, @RequestParam("file") MultipartFile[] file, @PathVariable(required = false) String taskId) {
3 fileService.upload(userPrincipal.getUser(), file, taskId);
4 return new ResponseEntity<>("File uploaded", HttpStatus.OK);
5}
6
If i try it to upload with a TaskId it works. But when i try it to upload without a taskId it doesnt work. I got the error:
"405 Method not allowed"
Does somebody know how to fix this?
ANSWER
Answered 2022-Jan-03 at 10:59If you want to use the @PathVariable
as an optional be sure to bind both paths: @PostMapping(value = {"/upload/{taskId}", "/upload"})
.
If you don't post the taskId
spring will look for a controller that handles "/upload"
instead of "/upload/{taskId}"
Personally i would use RequestParam
instead of PathVariable
for optional parameters
QUESTION
Antd File upload not getting reset
Asked 2021-Dec-20 at 09:58I have a form. where file upload is mandatory. Validation works fine first time no file uploaded, but when i upload and delete file, Form doesn't throw validation error. Here is stakbiz https://stackblitz.com/edit/react-x27nfd
ANSWER
Answered 2021-Dec-20 at 09:58You can use getValueFromEvent
prop on Form.Item
component like this:
1const normFile = (e) => {
2 if (Array.isArray(e)) {
3 return e;
4 }
5 return e && e.fileList;
6};
7...
8<Form.Item
9 label="File"
10 name="file"
11 getValueFromEvent={normFile}
12 rules={[
13 {
14 required: true,
15 message: 'Please input your File!',
16 },
17 ]}
18 >
19 ...
20</Form.Item>
21
Here is edited version of your stackblitz link.
QUESTION
Load byte[] Property of Class Only When Needed
Asked 2021-Dec-16 at 19:52I have a class that returns a List that is bound to a grid. One of my property is a byte[] array that should only be populated if someone double clicks on the cell in the grid cell with the file. At that point, the file should be downloaded an presented to the user. Just an event with a file name and Process.Start(...
Because I'm binding the list to the grid, it is calling the "File" property and filling the value giving it an eager type behavior rather than the lazy behavior I am looking for.
Is there any way I can stop this property from filling in the data class (below) without having to modify a UI level grid to explicitly not read the file column?
1public class Errors
2{
3//...
4 private bool hasFile;
5 public bool HasFile { get { return HasFile; } }
6 private byte[] file;
7 public byte[] File
8 {
9 get
10 {
11 if (HasFile) { file = FileHelper.DownloadAndDecompress(this.ID, "ErrorsDownloadFile"); }
12 return file;
13 }
14 set { file = value; }
15 }
16
17 public static List<Errors> FindByAppName(string AppName, DateTime StartDate, DateTime EndDate) {/*...*/}
18//...
19}
20
I did some reading on Lazy<T>
but, I'm struggling to get this to work into my regular workflow as when I implement it I can not assign to the setter the value to do file uploads...
Attempt but I can't assign a byte[] back to the File property as it is read only...
1public class Errors
2{
3//...
4 private bool hasFile;
5 public bool HasFile { get { return HasFile; } }
6 private byte[] file;
7 public byte[] File
8 {
9 get
10 {
11 if (HasFile) { file = FileHelper.DownloadAndDecompress(this.ID, "ErrorsDownloadFile"); }
12 return file;
13 }
14 set { file = value; }
15 }
16
17 public static List<Errors> FindByAppName(string AppName, DateTime StartDate, DateTime EndDate) {/*...*/}
18//...
19}
20public bool HasFile { get { return HasFile; } }
21public Lazy<byte[]> File
22{
23 get
24 {
25 if (HasFile) { return new Lazy<byte[]>(() => FileHelper.DownloadAndDecompress(this.ID, "ErrorsDownloadFile")); }
26 else { return null; };
27 }
28 set { }
29}
30
Any tips on how to properly implement a lazy property properly either using Lazy<T>
or another method would be very much appreciated.
ANSWER
Answered 2021-Dec-16 at 19:50If I understand you right, you want to implement lazy download, but eager upload
1public class Errors
2{
3//...
4 private bool hasFile;
5 public bool HasFile { get { return HasFile; } }
6 private byte[] file;
7 public byte[] File
8 {
9 get
10 {
11 if (HasFile) { file = FileHelper.DownloadAndDecompress(this.ID, "ErrorsDownloadFile"); }
12 return file;
13 }
14 set { file = value; }
15 }
16
17 public static List<Errors> FindByAppName(string AppName, DateTime StartDate, DateTime EndDate) {/*...*/}
18//...
19}
20public bool HasFile { get { return HasFile; } }
21public Lazy<byte[]> File
22{
23 get
24 {
25 if (HasFile) { return new Lazy<byte[]>(() => FileHelper.DownloadAndDecompress(this.ID, "ErrorsDownloadFile")); }
26 else { return null; };
27 }
28 set { }
29}
30// Eager download (will be used in lazy download)
31private byte[] DownLoad() {
32 // download here:
33 return FileHelper.DownloadAndDecompress(this.ID, "ErrorsDownloadFile");
34}
35
36// Lazy download ...
37private Lazy<byte[]> m_File;
38
39// ... which we assign in the constructor
40public MyClass() {
41 ...
42 m_File = new Lazy<byte[]>(Download);
43 ...
44}
45
46// Our property
47public byte[] File {
48 get {
49 // Lazy download
50 return m_File.Value;
51 }
52 set {
53 // we can't assign m_File.Value but we can recreate m_File
54 m_File = new Lazy<byte[]>(value);
55
56 //TODO: Upload here
57 }
58}
59
Community Discussions contain sources that include Stack Exchange Network
Tutorials and Learning Resources in File Upload
Tutorials and Learning Resources are not available at this moment for File Upload