After selecting an image file on the website, I wanted to POST the image with multipart / form-data with the upload button and save it to S3 on AWS, so I figured out how to do it. It may be helpful if you want to use AWS services, including saving images on your website.
We use ** HTML, CSS, JavaScript ** as the development language on the web side and ** Python 3.7 ** as the language on the Lambda side. The following are the services used.
** ・ AWS Lambda ** An AWS service that allows you to execute function code triggered by an event. **-Amazon S3 (used to save uploaded images and to publish websites) ** Abbreviation for Simple Storage Service, AWS online storage service
After POSTing the image in the form of multipart / form-data on the Web side using ajax, start Lambda by hitting API Gateway and save the image in S3 with the function in Lambda. As a bonus, store the file name of the saved image in the website's local storage so that you can browse the saved image.
It becomes the procedure.
This time, I took the form of POSTing to the API in the form of multipart / form-data from the website side. We also perform processing to prevent transition to another screen when the submit button is clicked, and change the style of various buttons.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--jquery library is not fixed-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<title>Title</title>
<style>
label > input {
display:none; /*Disable file button style*/
}
label > button {
display:none; /*Disable button style*/
}
label {
display: inline-block;
padding: 0.5em 1em;
text-decoration: none;
background: #fd9535;/*Button color*/
color: #FFF;
border-bottom: solid 4px #627295;
border-radius: 3px;
}
button{
display: inline-block;
padding: 0.5em 1em;
text-decoration: none;
background: #fd9535;/*Button color*/
color: #FFF;
border-bottom: solid 4px #627295;
border-radius: 3px;
}
label:active {
/*When you press the button*/
-webkit-transform: translateY(4px);
transform: translateY(4px);/*Move down*/
border-bottom: none;/*Erase the line*/
}
button:active{
/*When you press the button*/
-webkit-transform: translateY(4px);
transform: translateY(4px);/*Move down*/
border-bottom: none;/*Erase the line*/
}
</style>
</head>
<body>
<form action="xxx Where to enter the URL of API Gateway xxx" method="post" enctype="multipart/form-data" id="imgForm" target="sendPhoto">
<p>
<label for ="upfile">
Please select a file
<input type="file" name="fileName" id="upfile" accept="image/*" capture="camera">
</label>
<span style="color: #ff0000;" data-mce-style="color: #ff0000;"><div><img id="thumbnail" src=""></div></span>
</p>
<p>
<label for="upload">
upload
<button type="submit" action="" name="save" id="upload" >upload</button>
</label>
</p>
<p id="compUpload"></p>
</form>
<iframe name="sendPhoto" style="width:0px;height:0px;border:0px;"></iframe>
<script>
$('#upfile').change(function(){
if (this.files.length > 0) {
//Get selected file information
var file = this.files[0];
//Store the file data encoded as a data URL in the result property of reader
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function() {
$('#thumbnail').attr('src', reader.result );
}
}
});
//Upload image
$('#imgForm').on('submit', function(e) {
e.preventDefault();
var formData = new FormData($('#imgForm').get(0));
$.ajax($(this).attr('action'), {
type: 'post',
processData: false,
contentType: false,
data: formData,
success: document.getElementById('compUpload').innerHTML = 'Uploading' //When the transmission is successful
}).done(function(response){
let jsonbody = JSON.parse(response.body);
console.log('succes!'); //When there is a response
//Store response file name in local storage
var array = [];
var obj = {
'Key 1': 'Value 1',
'Key 2': 'Value 2'
};
array.push(obj);
var setjson = JSON.stringify(obj);
localStorage.setItem('Key', jsonbody.message);
document.getElementById('compUpload').innerHTML = 'Upload completed'
}).fail(function() {
console.log('error!'); //When an error occurs
});
return false;
});
</script>
</body>
</html>
Copy and paste the above code to create an html file. Place the file on your favorite server or S3 and view it. This completes the creation on the Web side except for "Specify the URL of API Gateway".
The code below is the specified part
python
<body>
<form action="xxx Where to enter the URL of API Gateway xxx" method="post" enctype="multipart/form-data" id="imgForm" target="sendPhoto">
I'll add this when I know the URL of the API Gateway in a later step to create a Lambda. Also, the default button was dull, so I changed the design with the style tag at the top of the code. The default display is hidden with display: none; and then changed to a new design.
python
<style>
label > input {
display:none; /*Disable file button style*/
}
label > button {
display:none; /*Disable button style*/
}
label {
display: inline-block;
padding: 0.5em 1em;
text-decoration: none;
background: #fd9535;/*Button color*/
color: #FFF;
border-bottom: solid 4px #627295;
border-radius: 3px;
}
button{
display: inline-block;
padding: 0.5em 1em;
text-decoration: none;
background: #fd9535;/*Button color*/
color: #FFF;
border-bottom: solid 4px #627295;
border-radius: 3px;
}
label:active {
/*When you press the button*/
-webkit-transform: translateY(4px);
transform: translateY(4px);/*Move down*/
border-bottom: none;/*Erase the line*/
}
button:active{
/*When you press the button*/
-webkit-transform: translateY(4px);
transform: translateY(4px);/*Move down*/
border-bottom: none;/*Erase the line*/
}
</style>
I'm using ajax to upload images. If the POST to the server side is successful, the web side will display "Uploading".
python
<script>
//Upload image
$('#imgForm').on('submit', function(e) {
e.preventDefault();
var formData = new FormData($('#imgForm').get(0));
$.ajax($(this).attr('action'), {
type: 'post',
processData: false,
contentType: false,
data: formData,
success: document.getElementById('compUpload').innerHTML = 'Uploading' //When the transmission is successful
}).done(function(response){
let jsonbody = JSON.parse(response.body);
console.log('succes!'); //When there is a response
//Store response file name in local storage
var array = [];
var obj = {
'Key 1': 'Value 1',
'Key 2': 'Value 2'
};
array.push(obj);
var setjson = JSON.stringify(obj);
localStorage.setItem('Key', jsonbody.message);
document.getElementById('compUpload').innerHTML = 'Upload completed'
}).fail(function() {
console.log('error!'); //When an error occurs
});
return false;
});
</script>
Use S3 as the location for uploading image files from the web. Select S3 from the AWS Management Console and create a bucket. It is recommended that the region specified at this time be the same as the region specified when Lambda is created later. (Because it may take time to reflect the settings in another region) ⇨ Reference link There is no problem with the setting at the time of creation by default, but in this article, uncheck'Block all public access'in the permission setting and set it to allow public access. (To display the response in Lambda on the web) If you want to set the access permission individually, please set it from the bucket policy after creation.
If you specify the path of the bucket created here in Lambda later, the uploaded image will be dropped.
In Lambda, the image POST on the Web side is triggered to run a function that saves the image in S3. To do this, first select Lambda from the AWS Management Console and click Create Function. At the time of creation, this article was created in the northern Virginia region. (It is recommended to make it the same as the region created in S3)
On the function creation screen, ・ Create from scratch -Function name (Enter your favorite function name) ・ Runtime (Python 3.7 is used this time) · Execution role (choose create new role with basic Lambda permissions)
After deciding these, click Create Function. Here, the function name is myFunctionName. The Run role allows access to S3 and CloudWatch, but first create it with basic Lambda permissions and add it later.
When the function creation is completed, the function edit screen opens. Click ** Add Trigger ** in the Designer window. The window will switch, so select ** API Gateway ** and make detailed settings.
On the Add Trigger screen, use the respective drop-down box and radio button choices. ・ API ⇨ Create new API -Select a template ⇨ REST API ・ Security ⇨ Open ・ Click additional settings ⇨ Added ** image / png ** and ** multipart / form-data ** to binary media types After that, click ** Add ** at the bottom right of the screen.
Then you should see API Gateway added to Designer as shown in the image below. This is a mechanism in which API Gateway receives a POST on the Web side and triggers the Lambda function to start.
When you click API Gateway in Designer, you will see a ** API endpoint ** that starts with https. Enter this URL as [Uncertain part in the website creation procedure](# The code below is -url-). Enter in (Part).
Next, click the "Function name-API" link displayed directly above the API endpoint to create an API method.
Click the "Function Name-API" link to open the API Gateway settings page. Now configure the API POST method to receive json-formatted files from your website.
Click ** Create Method ** from the action to display the select box (click the collapsible arrow to the right of the function name)
Select ** POST ** from the select box and click the checkmark
Select POST, select the Lambda region you are using on the screen that appears, then enter the function name you created earlier in the ** Lambda function ** input field and click Save.
Click OK if a window appears to add permissions to your Lambda function
Select Enable CORS from Actions, enter'true'in Advanced Access-Control-Allow-Credentials (including''), enable CORS and click Replace existing CORS header to value To add.
Select ** POST ** again, click ** Integration Request ** on the method execution screen, and map template ⇨ if no template is defined (recommended) ⇨ add mapping template ⇨ ** multipart / Enter form-data ** ⇨ Select ** Method request passthrough ** in Template generation and save
After clicking the Save button, select ** Function Name ** above ANY, select Deploy API from Actions, select default for the stage to be deployed, then click the Deploy button
This completes the API settings. Please note that there are many steps and it is easy to make mistakes. Next, we will move on to the function code settings, so please return to the Lambda function setting screen. You can return by service ⇨ Lambda ⇨ function name.
①
②
③
④
⑤
⑥
⑦
If you click the function name in Designer and scroll, there is an item to write the function code, so write the code in Python here. Here, the decoding of the image, the setting of the storage location, the response for acquiring the image name on the Web side, etc. are described.
lambda_function.py
import json
import boto3
import base64
from datetime import datetime, timezone
def convert_b64_string_to_bynary(s):
"""Decode base64"""
def lambda_handler(event, context):
#Image storage location setting
s3 = boto3.resource('s3')
bucket = s3.Bucket('xxx Name of bucket to store images xxx')
#The binary is Base64 encoded, so decode it here
imageBody = base64.b64decode(event['body-json'])
TextTime = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') #Set the uploaded image file name to the time at that time
images = imageBody.split(b'\r\n',4)#Cut only the necessary part with split
key = TextTime +".png "
bucket.put_object(
Body = images[4],
Key = key
)
#Return value to get the image name on the Web side
return {
'isBase64Encoded': False,
'statusCode': 200,
'headers': {'Access-Control-Allow-Origin' : '*' ,
'Content-Type' :'application/json'},
'body': '{"message":"'+ key + '"}'
}
After pasting the code, enter the S3 bucket name in the part below and save the state with the save button at the top right of the screen.
lambda_function.py
bucket = s3.Bucket('xxx Name of bucket to store images xxx')
Set an environment variable to adjust the timestamp to Japanese time. If you scroll down a little from the function code screen, you will find an item for environment variables. Follow the steps below to set environment variables.
If you scroll down a little from the environment variable item, you will find the execution role setting item. Follow the steps below to set the execution role.
This completes all the settings. Try uploading the image from the web screen, and if the image is saved in the corresponding bucket of S3, it is successful. As a bonus, you can also check that the file name is saved in the local storage at the upload time with the development tool. Please use it when you use a service that specifies the uploaded file.
This time, I used to refer to S3 images with a service called Amazon Rekognition Custom Labels on AWS, so I implemented such a function. If you are interested, please see the article below for the usability. About the usability of Amazon Rekognition Custom Labels
Why does Amazon S3 return an HTTP 307 Temporary Redirect response? How to prevent screen transition while performing POST processing with Form
Recommended Posts