Cloud Function yang mengurai permintaan formulir HTTP.
Contoh kode
C#
Untuk melakukan autentikasi ke Cloud Functions, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, baca Menyiapkan autentikasi untuk lingkungan pengembangan lokal.
using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace HttpFormData;
public class Function : IHttpFunction
{
private readonly ILogger _logger;
public Function(ILogger<Function> logger) =>
_logger = logger;
public async Task HandleAsync(HttpContext context)
{
HttpResponse response = context.Response;
HttpRequest request = context.Request;
if (request.Method != "POST")
{
response.StatusCode = (int) HttpStatusCode.MethodNotAllowed;
return;
}
// This code will process each file uploaded.
string tempDirectory = Path.GetTempPath();
foreach (IFormFile file in request.Form.Files)
{
if (string.IsNullOrEmpty(file.FileName))
{
continue;
}
_logger.LogInformation("Processed file: {file}", file.FileName);
// Note: GCF's temp directory is an in-memory file system
// Thus, any files in it must fit in the instance's memory.
string outputPath = Path.Combine(tempDirectory, file.FileName);
// Note: files saved to a GCF instance itself may not persist across executions.
// Persistent files should be stored elsewhere, e.g. a Cloud Storage bucket.
using (FileStream output = File.Create(outputPath))
{
await file.CopyToAsync(output);
}
// TODO(developer): process saved files here
File.Delete(outputPath);
}
// This code will process other form fields.
foreach (KeyValuePair<string, StringValues> parameter in request.Form)
{
// TODO(developer): process field values here
_logger.LogInformation("Processed field '{key}' (value: '{value}')",
parameter.Key, (string) parameter.Value);
}
}
}
Go
Untuk melakukan autentikasi ke Cloud Functions, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, baca Menyiapkan autentikasi untuk lingkungan pengembangan lokal.
// Package http provides a set of HTTP Cloud Functions samples.
package http
import (
"fmt"
"log"
"net/http"
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
)
// UploadFile processes a 'multipart/form-data' upload request.
func UploadFile(w http.ResponseWriter, r *http.Request) {
const maxMemory = 2 * 1024 * 1024 // 2 megabytes.
// ParseMultipartForm parses a request body as multipart/form-data.
// The whole request body is parsed and up to a total of maxMemory bytes of
// its file parts are stored in memory, with the remainder stored on
// disk in temporary files.
// Note that any files saved during a particular invocation may not
// persist after the current invocation completes; persistent files
// should be stored elsewhere, such as in a Cloud Storage bucket.
if err := r.ParseMultipartForm(maxMemory); err != nil {
http.Error(w, "Unable to parse form", http.StatusBadRequest)
log.Printf("Error parsing form: %v", err)
return
}
// Be sure to remove all temporary files after your function is finished.
defer func() {
if err := r.MultipartForm.RemoveAll(); err != nil {
http.Error(w, "Error cleaning up form files", http.StatusInternalServerError)
log.Printf("Error cleaning up form files: %v", err)
}
}()
// r.MultipartForm.File contains *multipart.FileHeader values for every
// file in the form. You can access the file contents using
// *multipart.FileHeader's Open method.
for _, headers := range r.MultipartForm.File {
for _, h := range headers {
fmt.Fprintf(w, "File uploaded: %q (%v bytes)", h.Filename, h.Size)
// Use h.Open() to read the contents of the file.
}
}
}
func init() {
functions.HTTP("UploadFile", UploadFile)
}
Java
Untuk melakukan autentikasi ke Cloud Functions, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, baca Menyiapkan autentikasi untuk lingkungan pengembangan lokal.
import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.logging.Logger;
public class HttpFormData implements HttpFunction {
private static final Logger logger = Logger.getLogger(HttpFormData.class.getName());
@Override
public void service(HttpRequest request, HttpResponse response)
throws IOException {
if (!"POST".equals(request.getMethod())) {
response.setStatusCode(HttpURLConnection.HTTP_BAD_METHOD);
return;
}
// This code will process each file uploaded.
String tempDirectory = System.getProperty("java.io.tmpdir");
for (HttpRequest.HttpPart httpPart : request.getParts().values()) {
String filename = httpPart.getFileName().orElse(null);
if (filename == null) {
continue;
}
logger.info("Processed file: " + filename);
// Note: GCF's temp directory is an in-memory file system
// Thus, any files in it must fit in the instance's memory.
Path filePath = Paths.get(tempDirectory, filename).toAbsolutePath();
// Note: files saved to a GCF instance itself may not persist across executions.
// Persistent files should be stored elsewhere, e.g. a Cloud Storage bucket.
Files.copy(httpPart.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
// TODO(developer): process saved files here
Files.delete(filePath);
}
// This code will process other form fields.
request.getQueryParameters().forEach(
(fieldName, fieldValues) -> {
String firstFieldValue = fieldValues.get(0);
// TODO(developer): process field values here
logger.info(String.format(
"Processed field: %s (value: %s)", fieldName, firstFieldValue));
});
}
}
Node.js
Untuk melakukan autentikasi ke Cloud Functions, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, baca Menyiapkan autentikasi untuk lingkungan pengembangan lokal.
/**
* Parses a 'multipart/form-data' upload request
*
* @param {Object} req Cloud Function request context.
* @param {Object} res Cloud Function response context.
*/
const path = require('path');
const os = require('os');
const fs = require('fs');
const functions = require('@google-cloud/functions-framework');
// Node.js doesn't have a built-in multipart/form-data parsing library.
// Instead, we can use the 'busboy' library from NPM to parse these requests.
const Busboy = require('busboy');
functions.http('uploadFile', (req, res) => {
if (req.method !== 'POST') {
// Return a "method not allowed" error
return res.status(405).end();
}
const busboy = Busboy({headers: req.headers});
const tmpdir = os.tmpdir();
// This object will accumulate all the fields, keyed by their name
const fields = {};
// This object will accumulate all the uploaded files, keyed by their name.
const uploads = {};
// This code will process each non-file field in the form.
busboy.on('field', (fieldname, val) => {
/**
* TODO(developer): Process submitted field values here
*/
console.log(`Processed field ${fieldname}: ${val}.`);
fields[fieldname] = val;
});
const fileWrites = [];
// This code will process each file uploaded.
busboy.on('file', (fieldname, file, {filename}) => {
// Note: os.tmpdir() points to an in-memory file system on GCF
// Thus, any files in it must fit in the instance's memory.
console.log(`Processed file ${filename}`);
const filepath = path.join(tmpdir, filename);
uploads[fieldname] = filepath;
const writeStream = fs.createWriteStream(filepath);
file.pipe(writeStream);
// File was processed by Busboy; wait for it to be written.
// Note: GCF may not persist saved files across invocations.
// Persistent files must be kept in other locations
// (such as Cloud Storage buckets).
const promise = new Promise((resolve, reject) => {
file.on('end', () => {
writeStream.end();
});
writeStream.on('close', resolve);
writeStream.on('error', reject);
});
fileWrites.push(promise);
});
// Triggered once all uploaded files are processed by Busboy.
// We still need to wait for the disk writes (saves) to complete.
busboy.on('finish', async () => {
await Promise.all(fileWrites);
/**
* TODO(developer): Process saved files here
*/
for (const file in uploads) {
fs.unlinkSync(uploads[file]);
}
res.send();
});
busboy.end(req.rawBody);
});
PHP
Untuk melakukan autentikasi ke Cloud Functions, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, baca Menyiapkan autentikasi untuk lingkungan pengembangan lokal.
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Psr7\Response;
function uploadFile(ServerRequestInterface $request): ResponseInterface
{
if ($request->getMethod() != 'POST') {
return new Response(405, [], 'Method Not Allowed: expected POST, found ' . $request->getMethod());
}
$contentType = $request->getHeader('Content-Type')[0];
if (strpos($contentType, 'multipart/form-data') !== 0) {
return new Response(400, [], 'Bad Request: content of type "multipart/form-data" not provided, found ' . $contentType);
}
$fileList = [];
/** @var $file Psr\Http\Message\UploadedFileInterface */
foreach ($request->getUploadedFiles() as $name => $file) {
// Use caution when trusting the client-provided filename:
// https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload
$fileList[] = $file->getClientFilename();
infoLog('Processing ' . $file->getClientFilename());
$filename = tempnam(sys_get_temp_dir(), $name . '.') . '-' . $file->getClientFilename();
// Use $file->getStream() to process the file contents in ways other than a direct "file save".
infoLog('Saving to ' . $filename);
$file->moveTo($filename);
}
if (empty($fileList)) {
$msg = 'Bad Request: no files sent for upload';
errorLog($msg);
return new Response(400, [], $msg);
}
return new Response(201, [], 'Saved ' . join(', ', $fileList));
}
function errorLog($msg): void
{
$stream = fopen('php://stderr', 'wb');
$entry = json_encode(['msg' => $msg, 'severity' => 'error'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
fwrite($stream, $entry . PHP_EOL);
}
function infoLog($msg): void
{
$stream = fopen('php://stderr', 'wb');
$entry = json_encode(['message' => $msg, 'severity' => 'info'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
fwrite($stream, $entry . PHP_EOL);
}
Python
Untuk melakukan autentikasi ke Cloud Functions, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, baca Menyiapkan autentikasi untuk lingkungan pengembangan lokal.
import os
import tempfile
import functions_framework
from werkzeug.utils import secure_filename
# Helper function that computes the filepath to save files to
def get_file_path(filename):
# Note: tempfile.gettempdir() points to an in-memory file system
# on GCF. Thus, any files in it must fit in the instance's memory.
file_name = secure_filename(filename)
return os.path.join(tempfile.gettempdir(), file_name)
@functions_framework.http
def parse_multipart(request):
"""Parses a 'multipart/form-data' upload request
Args:
request (flask.Request): The request object.
Returns:
The response text, or any set of values that can be turned into a
Response object using `make_response`
<http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
"""
# This code will process each non-file field in the form
fields = {}
data = request.form.to_dict()
for field in data:
fields[field] = data[field]
print("Processed field: %s" % field)
# This code will process each file uploaded
files = request.files.to_dict()
for file_name, file in files.items():
# Note: GCF may not keep files saved locally between invocations.
# If you want to preserve the uploaded files, you should save them
# to another location (such as a Cloud Storage bucket).
file.save(get_file_path(file_name))
print("Processed file: %s" % file_name)
# Clear temporary directory
for file_name in files:
file_path = get_file_path(file_name)
os.remove(file_path)
return "Done!"
Ruby
Untuk melakukan autentikasi ke Cloud Functions, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, baca Menyiapkan autentikasi untuk lingkungan pengembangan lokal.
require "functions_framework"
FunctionsFramework.http "http_form_data" do |request|
# The request parameter is a Rack::Request object.
# See https://www.rubydoc.info/gems/rack/Rack/Request
# This Rack call parses multipart form data, returning the params as a hash.
# The returned params hash includes an entry for each field. File uploads
# are written to Tempfiles and represented by hashes, while plain fields are
# represented by strings.
params = request.POST
begin
params.each do |name, part|
if part.is_a? Hash
# Handle a file upload part by logging the md5 hash.
md5 = Digest::MD5.hexdigest part[:tempfile].read
file_name = part[:filename]
logger.info "Processed file=#{file_name} md5=#{md5}"
else
# Handle a non-file part by logging the value.
logger.info "Processed field=#{name} value=#{part}"
end
end
ensure
# Ensure that all Tempfile objects are closed and deleted. The Cloud
# Functions runtime keeps temporary files in an in-memory file system,
# so to lower memory usage it is good practice to clean up Tempfiles
# explicitly rather than wait for object finalization.
params.each_value do |part|
part[:tempfile].close! if part.is_a? Hash
end
end
# The HTTP response body.
"OK"
end
Langkah selanjutnya
Untuk menelusuri dan memfilter contoh kode untuk produk Google Cloud lainnya, lihat browser contoh Google Cloud.