Оптимизация нескольких сетевых запросов

Я создал сервер обслуживания модели с библиотекой Python Tornado, и его единственная цель — принять http-запрос с полезной нагрузкой и вернуть результат в json. Запрос можно сделать с помощью application/json или multipart/form-data.

Для аутентификации и авторизации пользователей я сделал еще один сервер с библиотекой Golang echo. Таким образом, все запросы пользователей должны поступать сюда до того, как они достигнут моего сервера ресурсов.

Здесь у меня проблема, потому что моя программа требует изображений в качестве входных данных, поэтому пользователи отправят свой запрос с FormData. Когда он впервые попал на мой сервер Golang, мне нужно выполнить следующие шаги.

  1. Прочитайте файл формы.
  2. Сохраните его на локальном диске.
  3. Загрузите файл и сохраните его в байтовом буфере.
  4. Инициализировать составной модуль записи
  5. Сделать запрос на мой сервер ресурсов
  6. Получил результат, вернуть пользователю

Я чувствую, что это избыточно, поскольку я полагаю, что есть способ передать этот запрос непосредственно на мой сервер ресурсов (после выполнения аутентификации), без необходимости проходить через части ввода-вывода.

Мой код в настоящее время выглядит так, на данный момент аутентификация выполняется через промежуточное программное обеспечение. Есть ли способ оптимизировать этот поток?

func (h Handler) ProcessFormData(c echo.Context) error {

    // some validation

    file, err := c.FormFile("file")
    if err != nil {
        return c.JSON(http.StatusBadRequest, response.Exception{
            Code:   errcode.InvalidRequest,
            Detail: "Invalid file uploaded",
            Error:  err,
        })
    }

    filePath, err := fileUtil.SaveNetworkFile(file)
    if err != nil {
        return c.JSON(http.StatusInternalServerError, response.Exception{
            Code:   errcode.SystemError,
            Detail: "Error when processing file",
            Error:  err,
        })
    }

    f, err := os.Open(filePath)
    if err != nil {
        return c.JSON(http.StatusInternalServerError, response.Exception{
            Code:   errcode.SystemError,
            Detail: "Error when processing file",
            Error:  err,
        })
    }
    defer f.Close()

    fi, err := f.Stat()
    if err != nil {
        return c.JSON(http.StatusInternalServerError, response.Exception{
            Code:   errcode.SystemError,
            Detail: "Error when processing file",
            Error:  err,
        })
    }

    var body bytes.Buffer
    writer := multipart.NewWriter(&body)
    part, err := writer.CreateFormFile("file", fi.Name())
    if err != nil {
        return c.JSON(http.StatusInternalServerError, response.Exception{
            Code:   errcode.SystemError,
            Detail: "Error when processing file",
            Error:  err,
        })
    }

    if _, err := io.Copy(part, f); err != nil {
        return c.JSON(http.StatusInternalServerError, response.Exception{
            Code:   errcode.SystemError,
            Detail: "Error when processing file",
            Error:  err,
        })
    }
    writer.Close()

    req, err := http.NewRequest("POST", fmt.Sprintf("%s", env.ResourceServer), &body)
    req.Header.Set("Content-Type", writer.FormDataContentType())
    if err != nil {
        return c.JSON(http.StatusInternalServerError, response.Exception{
            Code:  errcode.APIRequestError,
            Error: err,
        })
    }

    client := &http.Client{}
    res, err := client.Do(req)
    if err != nil {
        return c.JSON(http.StatusInternalServerError, response.Exception{
            Code:   errcode.APIRequestError,
            Detail: "Error when posting request to resource server",
            Error:  err,
        })
    }

    defer res.Body.Close()

    data, _ := ioutil.ReadAll(res.Body)

    if res.StatusCode != 200 {
        errorData := &model.PanicResponse{}
        err := json.Unmarshal(data, errorData)
        if err != nil {
            return c.JSON(http.StatusInternalServerError, response.Exception{
                Code:  errcode.UnmarshalError,
                Error: err,
            })
        }

        return c.JSON(res.StatusCode, errorData)
    }

    result := &model.SuccessResponse{}
    err = json.Unmarshal(data, result)
    if err != nil {
        return c.JSON(http.StatusInternalServerError, response.Exception{
            Code:  errcode.UnmarshalError,
            Error: err,
        })
    }

    if fileUtil.IsFileExists(filePath) {
        fileUtil.DeleteFile(filePath)
    }

    // track and update usage
    userData := c.Get("USER")
    user := userData.(model.User)
    db.UpdateUsage(h.Db, &user.ID)

    return c.JSON(200, result)
}

person Moore Tech    schedule 11.01.2020    source источник
comment
Напрямую скопируйте файл формы в запрос, используя io.Copy(part, file). Удалите весь код, связанный с переменными f и filepath.   -  person Cerise Limón    schedule 11.01.2020
comment
Шаги 1, 2, 3 не требуются в зависимости от того, что показано здесь. Есть ли что-то в исключенном коде, для которого требуется временный файл?   -  person I Love Reflection    schedule 12.01.2020


Ответы (1)


Нашел решение благодаря комментарию @cerise-limón

По сути, мне нужно всего 2 строки

f, err := file.Open()
if _, err := io.Copy(part, f); err != nil {
    return c.JSON(http.StatusInternalServerError, response.Exception{
        Code:   errcode.SystemError,
        Detail: "Error when processing file",
    })
}
person Moore Tech    schedule 12.01.2020