Загрузить файл json из интерфейса js в серверную часть zhttp
У меня есть код js для загрузки файла json с содержимым
{"name": "John", "age": 35}
из внешнего интерфейса js с использованием POST в бэкэнд scala zhttp.JS-код:
<script>
async function loadJsonTests() {
console.log('Begin loading new JSON file with tests into server.');
let formData = new FormData();
let url = `load_test`;
formData.append("file", fileupload.files[0]);
let response = await fetch(url, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: formData
//body: JSON.stringify({name: 'John', age: 35})
});
return response.json();
}
async function btnUploadTestFile() {
const result = await loadJsonTests();
console.log(result);
}
</script>
html для загрузки файла и вызова функции js
<td width="70%" height="200px">
<input id="fileupload" type="file" name="fileupload" />
<br>
<div id="btn_upload_test_file" onclick="btnUploadTestFile()">send json file</div>
</td>
Часть Scala build.sbt
ThisBuild / scalaVersion := "2.12.15"
val Versions = new {
val zio = "2.0.5"
val zio_config = "3.0.7"
val z_http = "2.0.0-RC11"
val zio_json = "0.3.0-RC11"
}
lazy val dependencies =
new {
val zio = "dev.zio" %% "zio" % Versions.zio
val zio_conf = "dev.zio" %% "zio-config" % Versions.zio_config
val zio_conf_typesafe = "dev.zio" %% "zio-config-typesafe" % Versions.zio_config
val zio_conf_magnolia = "dev.zio" %% "zio-config-magnolia" % Versions.zio_config
val z_http = "io.d11" %% "zhttp" % Versions.z_http
val zio_json = "dev.zio" %% "zio-json" % Versions.zio_json
val zioDep = List(zio, zio_conf,zio_conf_typesafe,zio_conf_magnolia, z_http, zio_json )
}
Серверный код Scala
def apply(): Http[Any, Throwable, Request, Response] =
Http.collectZIO[Request] {
case req@(Method.POST -> !! / "load_test") => loadTest(req)
}
def loadTest(req: Request): ZIO[Any, Throwable, Response] =
for {
bodyStr <- req.body.asString
_ <- ZIO.logInfo(s"req JSON str = $bodyStr")
u <- req.body.asString.map(_.fromJson[User])
resp <- u match {
case Left(e) =>
ZIO.debug(s"Failed to parse the input: $e").as(
Response.text(e).setStatus(Status.BadRequest)
)
case Right(u) =>
ZIO.succeed(Response.json(u.toJson))
}
} yield resp
Когда я отправляю запрос от js, у меня возникает следующая ошибка:
message="req JSON str = ------WebKitFormBoundary11BJkIQrpt39tJXd
Content-Disposition: form-data; name="file"; filename="tests_set_1.json"
Content-Type: application/json
{"name": "John", "age": 35}
------WebKitFormBoundary11BJkIQrpt39tJXd--
" location=webui.WebUiApp.loadTest file=WebUiApp.scala line=51
Failed to parse the input: (expected '{' got '-')
Как я могу извлечь из тела только json-контент без дополнительной информации ------WebKitFormBoundary.....?
Если я отправлю json из js
body: JSON.stringify({name: 'John', age: 35})
, не файл, значит все ок.
3 ответа
Вы можете использоватьFileReader
чтобы получить содержимое файла, а затем отправить только содержимое
https://developer.mozilla.org/en-US/docs/Web/API/FileReader?retiredLocale=en
fileInputElement.change(function(e) {
var reader = new FileReader();
reader.onload = function(e) {
console.log(reader.result);
}
reader.readAsText(fileInput[0].files[0]);
});
Ваш сервер ожидает простое тело в виде строки, которую вы затем анализируете как JSON.
Но ваш интерфейс отправляет данные формы с файлом, это другой тип контента в HTTP-запросе.
Либо ваш бэкэнд должен быть изменен для чтения данных формы (вместо простой строки), либо в вашем интерфейсе нужно читать содержимое файла и отправлять только содержимое файла.
Исправлено с помощью следующего кода js:
<script>
function loadFile(file){
return new Promise(resolve=>{
let reader = new FileReader()
reader.onload = function(event) {
let data = event.target.result
resolve(data)
}
reader.readAsText(file)
})
}
async function loadJsonTests() {
console.log('Begin loading new JSON file with tests into server.');
var file = fileupload.files[0];
var fileContent = await loadFile(file);
console.log('-- request ----------------------------------------------');
console.log(fileContent);
console.log('---------------------------------------------------------');
const response = await fetch(`load_test`, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: fileContent
});
return response.json();
}
async function btnUploadTestFile() {
const resultJson = await loadJsonTests();
console.log('-- response ---------------------------------------------');
console.log(resultJson);
console.log('---------------------------------------------------------');
}
</script>