Estoy tratando de usar la función de nube para descargar un archivo JSON desde aquí: http://jsonplaceholder.typicode.com/posts? luego cárguelo en el depósito de Cloud Storage.
El registro de ejecución de la función parece estar bien, el estado devuelve 200. Sin embargo, el archivo JSON cargado en el depósito tiene solo 20 bytes y está vacío (mientras que el archivo original tiene ~27 KB)
Entonces, ayúdenme si me perdí algo, hay código y registros:
const {Storage} = require('@google-cloud/storage'); exports.writeToBucket = (req, res) => { const http = require('http'); const fs = require('fs'); const file = fs.createWriteStream("/tmp/post.json"); const request = http.get("http://jsonplaceholder.typicode.com/posts?", function(response) { response.pipe(file); }); console.log('file downloaded'); // Imports the Google Cloud client library const {Storage} = require('@google-cloud/storage'); // Creates a client const storage = new Storage(); const bucketName = 'tft-test-48c87.appspot.com'; const filename = '/tmp/post.json'; // Uploads a local file to the bucket storage.bucket(bucketName).upload(filename, { gzip: true, metadata: { cacheControl: 'no-cache', }, }); res.status(200).send(`${filename} uploaded to ${bucketName}.`); }; { "name": "sample-http", "version": "0.0.1", "dependencies": { "@google-cloud/storage": "^3.0.3" } }No escribo mucho NodeJS, pero creo que su problema es con el código asíncrono.
Usted crea la transmisión y luego emite el http.get pero no bloquea la devolución de llamada (canalización del archivo) antes de comenzar la carga de GCS.
Es posible que desee adjuntar un .on("finish", () => {...}) a la pipe y, en esa devolución de llamada, cargue el archivo en GCS.
NOTA IIRC GCS tiene un método que le permitirá escribir una secuencia directamente desde la memoria en lugar de pasar por un archivo.
NOTA : si coloca el objeto de
storageen el espacio de nombres global, solo se creará cada vez que se cree la instancia y no cada vez que se invoque la función.
Como señaló @DazWilkin , hay problemas con el código asíncrono. Debe esperar a que onfinish() y luego continuar. Además, el método upload() también devuelve una promesa. Intente refactorizar su función en la sintaxis async-await como se muestra a continuación:
exports.writeToBucket = async (req, res) => { const http = require('http'); const fs = require('fs'); // Imports the Google Cloud client library const {Storage} = require('@google-cloud/storage'); // Creates a client const storage = new Storage(); const bucketName = 'tft-test-48c87.appspot.com'; const filename = '/tmp/post.json'; await downloadJson() // Uploads a local file to the bucket await storage.bucket(bucketName).upload(filename, { gzip: true, metadata: { cacheControl: 'no-cache', }, }); res.status(200).send(`${filename} uploaded to ${bucketName}.`); } const downloadJson = async () => { const Axios = require('axios') const fs = require("fs") const writer = fs.createWriteStream("/tmp/post.json") const response = await Axios({ url: "http://jsonplaceholder.typicode.com/posts", method: 'GET', responseType: 'stream' }) response.data.pipe(writer) return new Promise((resolve, reject) => { writer.on('finish', resolve) writer.on('error', reject) }) } Este ejemplo usa Axios pero puede hacer lo mismo con http .
Tenga en cuenta que puede cargar directamente el JSON obtenido como un archivo como este:
exports.writeToBucket = async (req, res) => { const Axios = require("axios"); const { Storage } = require("@google-cloud/storage"); const storage = new Storage(); const bucketName = "tft-test-48c87.appspot.com"; const filename = "/tmp/post.json"; const { data } = await Axios.get("http://jsonplaceholder.typicode.com/posts"); const file = storage.bucket(bucketName).file("file.json"); const contents = JSON.stringify(data); await file.save(contents); res.status(200).send(`${filename} uploaded to ${bucketName}.`); }; Puede leer más sobre el método save() en la documentación .
No necesita un flujo de escritura para obtener los datos de la URL, obtener la URL, esperar la respuesta para resolver, llamar al método response.toJson() apropiado.
Personalmente, prefiero usar Fetch y Axios en lugar de http , ya que son más limpios para trabajar. Pero con Nodes http puedes hacer lo siguiente:
https.get(url,(res) => { let body = ""; res.on("data", (chunk) => { body += chunk; }); res.on("end", () => { try { let json = JSON.parse(body); // do something with JSON } catch (error) { console.error(error.message); }; }); }).on("error", (error) => { console.error(error.message); });Una vez que tenga eso, puede pasarlo directamente a un método de almacenamiento como un blob de datos o una matriz de bytes.
byte[] byteArray = resultJson.toString().getBytes("UTF-8");