Comment simuler le téléchargement de formulaires post-objet vers OSS en Java

** Alibaba Cloud Object Storage Service (OSS) ** stocke les objets dans des ressources appelées «buckets». L'objet de publication utilise un formulaire HTML pour télécharger le fichier dans le compartiment spécifié.

Préface

Alibaba Cloud Object Storage Service (OSS) est un service facile à utiliser qui vous permet de stocker, sauvegarder et archiver de grandes quantités de données dans le cloud. OSS agit comme un référentiel central chiffré, vous donnant un accès sécurisé aux fichiers du monde entier. De plus, avec une disponibilité garantie jusqu'à 99,9%, il est idéal pour les équipes mondiales et la gestion de projets internationaux.

Alibaba Cloud Object Storage Service (OSS) stocke en toute sécurité les objets dans des ressources appelées «buckets». OSS vous donne un accès complet aux compartiments et vous permet d'afficher les journaux et les objets dans chaque compartiment. Vous pouvez lire, écrire, supprimer et enregistrer un nombre illimité d'objets dans votre compartiment. Les hautes performances d'OSS prennent en charge plusieurs lectures / écritures en même temps. Le transfert de données vers le compartiment s'effectue via SSL et est chiffré.

Post Object utilise des formulaires HTML au lieu de Put pour télécharger des fichiers dans le compartiment spécifié. Cela vous permet de télécharger des fichiers dans votre bucket via votre navigateur. Le désir d'implémenter Post Object en Java vient des brèves explications de divers personnels de support. Selon eux, les utilisateurs qui ont besoin de cette fonctionnalité sont confrontés à divers problèmes difficiles lorsqu'ils tentent de mettre en œuvre la fonctionnalité selon la documentation officielle. Cela se produit parce qu'il n'y a pas de référence de code officielle.

Flux de procédure

Jetons un coup d'œil aux étapes que l'utilisateur doit suivre.

Ensuite, j'expliquerai les deux aspects mentionnés ci-dessus.

Pour une introduction détaillée à multipart / form-data, voir RFC 2388. Il y a quelques points à noter ici. Discutons-en un par un.

  1. Au premier point, la requête "multipart / form-data" contient une série de champs. Chaque champ a un en-tête de disposition de contenu de type "form-data". Cet en-tête contient également le paramètre "nom" pour décrire le contenu des champs du formulaire. Par conséquent, tous les champs ont un format similaire à l'exemple montré dans la documentation.

Content-Disposition: form-data; name=“your_key"

Remarque: les deux ":" et ";" suivent l'espace.

  1. Le deuxième point à noter est que si vous devez télécharger un fichier utilisateur dans un formulaire, vous aurez peut-être besoin du nom de fichier et d'autres attributs de fichier dans l'en-tête Content-disposition. En outre, il existe un attribut Content-Type facultatif pour identifier le type de contenu du fichier pour toute valeur de type MIME dans le champ de formulaire. Par conséquent, la documentation répertorie des exemples de champs de formulaire "fichier" comme suit:
Content-Disposition: form-data; name="file"; filename="MyFilename.jpg "
Content-Type: image/jpeg

Remarque: Le ";" avant le "nom de fichier" a toujours un espace à la fin. De même, il y a un espace de fin dans le ":" après le "Content-Type".

  1. Le troisième point est de séparer les données par une bordure. Utilisons une bordure complexe pour la distinguer du contenu principal. Cela peut être réalisé d'une manière similaire au contenu des en-têtes HTTP, comme décrit dans la documentation.

Content-Type: multipart/form-data; boundary=9431149156168

  1. Le quatrième point à noter est que la structure de chaque champ de formulaire est fixe. De par sa conception, chaque champ de formulaire commence par "-" boundary +, suivi d'un retour chariot (/ r / n). Ceci est suivi de la description du champ de formulaire (voir point 1), puis / r / n. Si le contenu que vous souhaitez transférer est un fichier, les informations sur le nom du fichier incluent également le retour chariot (/ r / n) suivi du type de contenu du fichier (voir point 2). De plus, il existe un autre retour chariot (/ r / n) pour démarrer le contenu réel, qui doit se terminer à / r / n.

  2. Notez également que le dernier champ de formulaire se termine par "-" + limite + "-".

  3. De plus, la marque / r / n est nécessaire pour faire la distinction entre les en-têtes de requête HTTP et les informations de corps (à la jonction de l'en-tête et du premier champ de formulaire). Il s'agit essentiellement d'une ligne vierge supplémentaire comme un document, qui ressemble à ceci:

Content-Type: multipart/form-data; boundary=9431149156168

--9431149156168
Content-Disposition: form-data; name="key"

Jusqu'à présent, nous avons fourni une description générale de la syntaxe de requête fournie dans la documentation officielle OSS et une analyse connexe par comparaison avec la norme RFC 2388.

Dans cette section, nous allons approfondir certaines des mises en garde associées à certains des traitements que le système OSS effectue pour analyser les demandes d'objet POST.

La procédure générale pour OSS pour analyser une requête POST est illustrée dans la figure ci-dessous pour référence.

image.png

Le flux de traitement des demandes est résumé en trois étapes principales.

  1. Analysez les limites des en-têtes de requête HTTP pour distinguer les limites des champs.
  2. Analysez le contenu de divers champs jusqu'à ce que le flux atteigne le champ de formulaire "fichier".
  3. Analysez le champ file'form.

Par conséquent, la documentation insiste sur le fait de placer le champ "fichier" dans le "dernier champ". Sinon, les champs de formulaire après "fichier" peuvent n'avoir aucun effet. Le fait de placer le champ de formulaire requis «clé» après «fichier» garantit que le résultat est un InvalidArgument.

Ensuite, je vais expliquer brièvement le flux de travail comme indiqué dans la figure.

  1. Vérifiez l'existence de POLICY, OSSACCESSKEYID et SIGNATURE. Cette vérification est obligatoire. Si l'un des trois champs POLICY, OSSACCESSKEYID et SIGNATURE apparaît, les deux autres champs sont obligatoires.
  2. Existence d'une autorité. Vérifiez la validité de la demande de publication sur la base des informations de POLICY, OSSACCESSKEYID et SIGNATURE.
  3. Vérification des règles de politique Vérifiez si les paramètres des différents champs de formulaire de la demande sont conformes aux paramètres de stratégie.
  4. Vérifiez la légalité de la longueur.

Ceci est destiné à vérifier la longueur du champ d'options en raison de la longueur totale limitée du corps de la demande de publication. 5) Analysez ParseContentType avec ParseFile. Analyse le champ ContentType dans le champ Fichier. Ce champ n'est pas obligatoire.

Cela se termine avec le code Java (projet Maven) qui implémente le téléchargement de Post Object dans OSS pour référence et utilisation par ceux qui sont familiers avec OSS.

import javax.activation.MimetypesFileTypeMap;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by yushuting on 16/4/17.
 */
public class OssPostObject {

    private String postFileName = "your_file";  
Make sure that the file exists at the path indicated in the run code. 
    private String ossEndpoint = "your_endpoint";  
For example: http://oss-cn-shanghai.aliyuncs.com
    private String ossAccessId = "your_accessid";  This is your access AK
    private String ossAccessKey = "your_accesskey";  This is your access AK
    private String objectName = "your_object_name";  This is the object name after you upload the file
    private String bucket = "your_bucket";  Make sure that the bucket you created previously has been created. 

    private void PostObject() throws Exception {

        String filepath=postFileName;
        String urlStr = ossEndpoint.replace("http://", "http://"+bucket+".");  This is the URL for the submitted form is the bucket domain name

        LinkedHashMap<String, String> textMap = new LinkedHashMap<String, String>();
        // key
        String objectName = this.objectName;
        textMap.put("key", objectName);
        // Content-Disposition
        textMap.put("Content-Disposition", "attachment;filename="+filepath);
        // OSSAccessKeyId
        textMap.put("OSSAccessKeyId", ossAccessId);
        // policy
        String policy = "{\"expiration\": \"2120-01-01T12:00:00.000Z\",\"conditions\": [[\"content-length-range\", 0, 104857600]]}";
        String encodePolicy = java.util.Base64.getEncoder().encodeToString(policy.getBytes());
        textMap.put("policy", encodePolicy);
        // Signature
        String signaturecom = com.aliyun.oss.common.auth.ServiceSignature.create().computeSignature(ossAccessKey, encodePolicy);
        textMap.put("Signature", signaturecom);

        Map<String, String> fileMap = new HashMap<String, String>();
        fileMap.put("file", filepath);

        String ret = formUpload(urlStr, textMap, fileMap);
        System.out.println("[" + bucket + "] post_object:" + objectName);
        System.out.println("post reponse:" + ret);
    }

    private static String formUpload(String urlStr, Map<String, String> textMap, Map<String, String> fileMap) throws Exception {
        String res = "";
        HttpURLConnection conn = null;
        String BOUNDARY = "9431149156168";
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("User-Agent",
                    "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + BOUNDARY);

            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // text
            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator iter = textMap.entrySet().iterator();
                int i = 0;
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    if (i == 0) {
                        strBuf.append("--").append(BOUNDARY).append(
                                "\r\n");
                        strBuf.append("Content-Disposition: form-data; name=\""
                                + inputName + "\"\r\n\r\n");
                        strBuf.append(inputValue);
                    } else {
                        strBuf.append("\r\n").append("--").append(BOUNDARY).append(
                                "\r\n");
                        strBuf.append("Content-Disposition: form-data; name=\""
                                + inputName + "\"\r\n\r\n");

                        strBuf.append(inputValue);
                    }

                    i++;
                }
                out.write(strBuf.toString().getBytes());
            }

            // file
            if (fileMap != null) {
                Iterator iter = fileMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    File file = new File(inputValue);
                    String filename = file.getName();
                    String contentType = new MimetypesFileTypeMap().getContentType(file);
                    if (contentType == null || contentType.equals("")) {
                        contentType = "application/octet-stream";
                    }

                    StringBuffer strBuf = new StringBuffer();
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append(
                            "\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"; filename=\"" + filename
                            + "\"\r\n");
                    strBuf.append("Content-Type: " + contentType + "\r\n\r\n");

                    out.write(strBuf.toString().getBytes());

                    DataInputStream in = new DataInputStream(new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[1024];
                    while ((bytes = in.read(bufferOut)) != -1) {
                        out.write(bufferOut, 0, bytes);
                    }
                    in.close();
                }
                StringBuffer strBuf = new StringBuffer();
                out.write(strBuf.toString().getBytes());
            }

            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();

            // Read the returned data
            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            System.err.println("Error in sending a POST request:  " + urlStr);
            throw e;
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return res;
    }

    public static void main(String[] args) throws Exception {
        OssPostObject ossPostObject = new OssPostObject();
        ossPostObject.PostObject();
    }

}

Veuillez noter que vous devez ajouter ce qui suit à pom.xml.

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>2.2.1</version>
</dependency>

Conclusion

Post Object vous permet de télécharger des fichiers dans votre compartiment en fonction de votre navigateur. Le codage du corps du message Post Object utilise des données multipart / form. Dans les opérations Post Object, le programme transfère les paramètres sous forme de champs de formulaire dans le corps du message. Post Object utilise AccessKeySecret pour calculer la signature de la stratégie. Le champ de formulaire POST est une option pour télécharger des compartiments publics en lecture / écriture, mais nous vous recommandons d'utiliser ce champ pour limiter les demandes POST.

Recommended Posts

Comment simuler le téléchargement de formulaires post-objet vers OSS en Java
Comment afficher une page Web en Java
Comment créer un environnement Java en seulement 3 secondes
Comment créer un URI de données (base64) en Java
Comment convertir A en A et A en A en utilisant le produit logique et la somme en Java
Comment convertir un fichier en tableau d'octets en Java
Comment créer un conteneur Java
Comment nommer des variables en Java
Comment développer et enregistrer une application Sota en Java
Comment créer un tableau Java
Comment concaténer des chaînes avec Java
Comment implémenter un travail qui utilise l'API Java dans JobScheduler
Comment créer un nouveau projet Gradle + Java + Jar dans Intellij 2016.03
Comment implémenter le calcul de la date en Java
Comment implémenter le filtre de Kalman par Java
Prise en charge multilingue de Java Comment utiliser les paramètres régionaux
Comment insérer une vidéo dans Rails
Comment faire une conversion de base en Java
Comment créer un robot Discord (Java)
Comment appliquer les conventions de codage en Java
Comment intégrer Janus Graph dans Java
Comment publier une bibliothèque dans jCenter
Comment tester une méthode privée et la simuler partiellement en Java
[Mémo personnel] Comment interagir avec le générateur de nombres aléatoires en Java
Comment passer un proxy lors du lancement de REST avec SSL en Java
Comment obtenir le chemin absolu d'un répertoire s'exécutant en Java
[Java] [Pour les débutants] Comment insérer des éléments directement dans un tableau à deux dimensions
Deux façons de démarrer un thread en Java + @
Code pour échapper aux chaînes JSON en Java
Essayez de créer un babillard en Java
Comment obtenir une classe depuis Element en Java
Je voulais que (a == 1 && a == 2 && a == 3) vrai en Java
Comment exécuter une tâche djUnit dans Ant
Comment ajouter un chemin de classe dans Spring Boot
Comment créer un thème dans Liferay 7 / DXP
Comment implémenter une fonctionnalité similaire dans Rails
Comment créer facilement un pull-down avec des rails
Comment résoudre les problèmes d'expression en Java
Comment écrire Java String # getBytes dans Kotlin?
Comment générer automatiquement un constructeur dans Eclipse
Comment compresser un fichier JAVA CSV et le gérer dans un tableau d'octets
Comment stocker simultanément des données dans un modèle associé à une forme imbriquée (Rails 6.0.0)
Comment effacer toutes les données d'une table particulière
Comment appeler des fonctions en bloc avec la réflexion Java
[Java] Comment omettre le constructeur privé dans Lombok
Comment implémenter une fonctionnalité intéressante dans Ajax avec Rails
Comment passer d'Eclipse Java à un fichier SQL
Comment entrer / sortir des fichiers mainframe IBM en Java?
java: Comment écrire une liste de types génériques [Note]
[Java] Comment sortir de Janken (équivalent à paiza rang A)
Comment créer un projet Spring Boot dans IntelliJ
[Java] Comment obtenir une requête par communication HTTP
J'ai essayé de créer une fonction de connexion avec Java
Comment afficher un aperçu du navigateur avec VS Code
[Comment insérer une vidéo dans un hameau avec Rails]
Comment écrire une recherche de comparaison de dates dans Rails