从 NativeScript 上传到 Rails Shrine



我正在使用带有Shrine宝石的Rails 5.2进行图像上传。在客户端,我正在使用NativeScript 6.0和Angular 8.0。

我已经安装了 Shrine,它正在 Rails 端工作并通过 Uppy 直接上传。

在使用NativeScript的前端(Android移动设备(上,我可以拍摄一张照片(使用nativescript-camera(并使用nativescript-background-http将其发送到nativescript-background-http演示服务器(基于节点(。

我遇到的问题是从NativeScript发送到Shrine。

在后端我有这些路由

Rails.application.routes.draw do
resources :asset_items
mount ImageUploader.upload_endpoint(:cache) => "/images/upload" # POST /images/upload
end

在我的神龛设置中,我有

require "shrine"
require "shrine/storage/file_system"
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), 
store: Shrine::Storage::FileSystem.new("public", prefix: "uploads"),           }
Shrine.plugin :logging, logger: Rails.logger
Shrine.plugin :upload_endpoint
Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data
Shrine.plugin :restore_cached_data

在前端

onTakePictureTap(args) {
requestPermissions().then(
() => {
var imageModule = require("tns-core-modules/ui/image");
takePicture({width: 150, height: 100, keepAspectRatio: true})
.then((imageAsset: any) => {
this.cameraImage = imageAsset;
let image = new imageModule.Image();
image.src = imageAsset;
this._dataItem.picture_url = this.imageAssetURL(imageAsset);
// Send picture to backend
var file =  this._dataItem.picture_url;
var url = "https://192.168.1.4/images/upload";
var name = file.substr(file.lastIndexOf("/") + 1);
// upload configuration
var bghttp = require("nativescript-background-http");
var session = bghttp.session("image-upload");
var request = {
url: url,
method: "POST",
headers: {
"Content-Type": "application/octet-stream"
},
description: "Uploading " + name
};
var task = session.uploadFile(file, request);
task.on("error", this.errorHandler);
task.on("responded", this.respondedHandler);
task.on("complete", this.completeHandler);
}, (error) => {
console.log("Error: " + error);
});
},
() => alert('permissions rejected')
);
} // onTakePictureTap

处理程序看起来像这样

errorHandler(e) {
alert("received " + e.responseCode + " code.");
var serverResponse = e.response;
}
respondedHandler(e) {
alert("received " + e.responseCode + " code. Server sent: " + e.data);
}
completeHandler(e) {
alert("received")
}

当我拍照时,它会尝试将其发送到后端,并在服务器上获得以下日志;

Started POST "/images/upload" for 103.232.216.30 at 2019-08-14 11:14:09 +1000
Cannot render console from 103.232.216.30! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255

我认为问题出在我发送到 Shrine 的标头中,将图像从 NativeScript 发送到 Shine 的正确方法是什么?

更新:尝试分段上传

我尝试了多部分上传,也得到了 400 错误代码

// upload configuration
var bghttp = require("nativescript-background-http");
var session = bghttp.session("image-upload");
var request = {
url: url,
method: "POST",
headers: {
"Content-Type": "application/octet-stream"
},
description: "Uploading " + name
};
var params = [
{
name: "fileToUpload.jpg",
filename: file,
mimeType: "image/jpeg"
}
];
var task = session.multipartUpload(params, request);

**更新:尝试本机脚本-后台-http演示服务器

这行得通,我可以成功地将多部分上传发送到演示服务器

更新:中间件到日志请求

开始整理中间件机架类以打印出响应

class MyMiddleware
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
puts "Middleware called. Status: #{status}, Headers: #{headers}"
[status, headers, body]
end
end

当我发送文件时,它会发送响应

Middleware called. Status: 400, Headers: {"Content-Type"=>"text/plain", "Content-Length"=>"16"}

从 NativeScript 发送时查看 byebug 中的标头、状态和正文;

(byebug) headers
{"Content-Type"=>"text/plain", "Content-Length"=>"16", "Cache-Control"=>"no-cache", "X-Request-Id"=>"7a5d40e2-5c09-4fc7-88b5-83813cedf20e", "X-Runtime"=>"0.055892"}

(byebug) status
400

(byebug) body
#<Rack::BodyProxy:0x000056471192c580 @body=#<Rack::BodyProxy:0x000056471192c620 @body=#<Rack::BodyProxy:0x000056471192c878 @body=#<Rack::BodyProxy:0x000056471192c968 @body=#<Rack::BodyProxy:0x000056471192cdc8 @body=["Upload Not Found"], @block=#<Proc:0x000056471192cd28@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/tempfile_reaper.rb:16>, @closed=false>, @block=#<Proc:0x000056471192c918@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/executor.rb:15>, @closed=false>, @block=#<Proc:0x000056471192c850@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/railties-5.2.3/lib/rails/rack/logger.rb:39>, @closed=false>, @block=#<Proc:0x000056471192c5d0@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activesupport-5.2.3/lib/active_support/cache/strategy/local_cache_middleware.rb:30>, @closed=false>, @block=#<Proc:0x000056471192c508@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/executor.rb:15>, @closed=false>

通过 Rails 端的 Uppy 成功发送会显示此结果

(byebug) headers
{"Content-Type"=>"application/json; charset=utf-8", "Content-Length"=>"149", "ETag"=>"W/"29040a3f35783193f7ba450aac8906bd"", "Cache-Control"=>"max-age=0, private, must-revalidate", "X-Request-Id"=>"53b380b8-e902-49d3-885f-634fc9ea82dc", "X-Runtime"=>"0.028117"}

(byebug) body
#<Rack::BodyProxy:0x00007f2c801f8868 @body=#<Rack::BodyProxy:0x00007f2c801f8980 @body=#<Rack::BodyProxy:0x00007f2c801f8de0 @body=#<Rack::BodyProxy:0x00007f2c801f90b0 @body=#<Rack::BodyProxy:0x00007f2c801f98f8 @body=["{"id":"85bf685af3b7965c701227478e2189a2.jpg","storage":"cache","metadata":{"filename":"DSCF3107_edited.JPG","size":3998332,"mime_type":"image/jpeg"}}"], @block=#<Proc:0x00007f2c801f9858@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/etag.rb:30>, @closed=false>, @block=#<Proc:0x00007f2c801f8f98@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/executor.rb:15>, @closed=false>, @block=#<Proc:0x00007f2c801f8db8@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/railties-5.2.3/lib/rails/rack/logger.rb:39>, @closed=false>, @block=#<Proc:0x00007f2c801f8890@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activesupport-5.2.3/lib/active_support/cache/strategy/local_cache_middleware.rb:30>, @closed=false>, @block=#<Proc:0x00007f2c801f8750@/usr/local/rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/executor.rb:15>, @closed=false>

来自Chrome网络的信息通过Uppy成功上传

- General
: Request URL: http://localhost:9000/images/upload
: Request Method: POST
: Status Code: 200 OK
: Remote Address: [::1]:9000
: Referrer Policy: strict-origin-when-cross-origin
- Response                
: Cache-Control: max-age=0, private, must-revalidate
: Content-Length: 141
: Content-Type: application/json; charset=utf-8
: ETag: W/"8e3a470866888e1d724013e95d0a49b4"
: X-Request-Id: 3e4222bd-e5bf-4270-bc31-1fc2c25696b1
: X-Runtime: 0.010884
- Request
: Accept: */*
: Accept-Encoding: gzip, deflate, br
: Accept-Language: en-US,en;q=0.9
: Cache-Control: no-cache
: Connection: keep-alive
: Content-Length: 110221
: Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRJtv5UR0QTM2J2x
: Cookie: _session_id=73b3a497c62bd745a789bc00b9f14361; org.cups.sid=c9eb7594a0515f4965b7a8e2f7900050; io=aArI7Q_64r2LWkc5AAAA; CSRF-Token-4MYJC=hLjA49c9bSsUhMUrYMfgSFSEnquQufo3; CSRF-Token-CAGDA=53tpJXxkvAstfeCoAKKbWgQDiQpU7xLj; CSRF-Token-TUFRR=kAWjSsQW4YCdEyGtaNKpfPT4gjToabYL; XSRF-TOKEN=HCjw%2B3WTJcSd1ddt45JGGGo8Uer43ggZZRrcsLc2NFgTdghJ852fqo0rWUx0%2FfBIOfv9YEMJ7mXw8TCix7d2cA%3D%3D; CSRF-Token-XDZDE=LyXXMXei6ci6FHrE3MfTxn3ARAKXYgMZ; _personal_property_rails_prototype_session=u65TkCvL9slUmGQQsP37lJH0BPcMw0E5%2FaDNw6frbuFw8NwqfM9gYPp%2F%2F830NFeZJqwxnYqc%2FCP%2FPIXhvPGFbD4waESKMKS1ChILCxTXZAPRFFULtu9m4Xl2G6AlF0ZamkzY7sdcE15vnpIBm8M%3D--98yhZGLNKsL5dnSX--Radl4qCShjACiTHc5UTH1A%3D%3D
: Host: localhost:9000
: Origin: http://localhost:9000
: Pragma: no-cache
: Referer: http://localhost:9000/asset_items/new
: User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
- Form data
: name: 2014-mlug.png
: type: image/png
: files[]: (binary)

更新:可以使用blob通过Angular上传

我可以使用blob从Angular 8.0上传到Shrine。

sendImage(files: FileList){
this.image = files.item(0);
var directUrl = "http://localhost:9000/images/upload";
// Create a formData object
const formData: FormData = new FormData();
formData.append('file', files.item(0), this.image.name);
// Direct Upload
this.http.post(directUrl, formData).subscribe(event => {
console.log("Successfully uploaded: " + event);
this.asset.image = JSON.stringify(event);
});
}

更新:尝试 nativescript-http-formdata

这是我通过 nativescript-http-formdata 发送图片的实现;

async sendPicture(filepath, imageAsset) {
var url = "http://localhost:9000/images/upload";
var name = filepath.substr(filepath.lastIndexOf("/") + 1);
// Get bitmap of file
const imageAndroidBitmap = android.graphics.BitmapFactory.decodeFile(filepath);
// Prepare the formdata
let fd = new TNSHttpFormData();
let param: TNSHttpFormDataParam = {
data: imageAndroidBitmap,
contentType: 'image/jpeg',
fileName: 'test.jpg',
parameterName: 'file1'
};
let params = [];
params.push(param);
try {
const response: TNSHttpFormDataResponse = await fd.post(url, params, {
headers: {}
});
console.log(response);
} catch (e) {
console.log(e);
}

错误:查看此错误后,我认为 okhttp3 已加载,但语法对于 NativeScript 6.0 来说是错误的

LOG from device Galaxy S8: Error: java.lang.Exception: Failed resolving method create on class okhttp3.RequestBody

更新:通过卷曲上传到神社=作品

尝试了以下操作,并得到相同的错误请求400错误;

发送图片

curl -X POST --form "file=@t-bird.jpg" http://localhost:9000/images/upload
{"id":"4b4d42e77b4fa7ecddbd93cd07845cc2.jpg","storage":"cache","metadata":{"filename":"t-bird.jpg","size":1478512,"mime_type":"image/jpeg"}}
*NOTE: when we send the picture we use 'file' instead of 'image'*

发送文本表单(可选(

curl -X POST -d "asset_item[name]=curl" http://localhost:9000/asset_items.json

将输出转换为 JSON

irb
{id:"7276dc618cdd23bf3f5a9243d3c59399.jpg",storage:"cache",metadata:{filename:"t-bird.jpg",size:1478512,mime_type:"image/jpeg"}}.to_json

结果

"{"id":"7276dc618cdd23bf3f5a9243d3c59399.jpg","storage":"cache","metadata":{"filename":"t-bird.jpg","size":1478512,"mime_type":"image/jpeg"}}"

使用图像数据发布文本

curl -X POST -d "asset_item[name]=curl" -d 'asset_item[image]="{"id":"7276dc618cdd23bf3f5a9243d3c59399.jpg","storage":"cache","metadata":{"filename":"t-bird.jpg","size":1478512,"mime_type":"image/jpeg"}}"' http://localhost:9000/asset_items.json

电流通过

我认为我目前最好的机会是使用 nativescript-background-http 以正确的格式向 shrine 发送多部分帖子。那是什么。

因为您成功地在角度项目中使用blob上传。您应该使用nativescript-http-formdata插件。您可以从 npmtns plugin add nativescript-http-formdata下载此存储库,也可以在此处找到存储库。

附言这个插件依赖于 Okhttp,所以你需要在你的 app.gradle 文件中添加以下内容

dependencies {
compile "com.squareup.okhttp3:okhttp:3.10.0"
}

我设法发送了一张图像,我一直遇到的主要问题是我必须在NativeScript-background-http插件中的multipartUpload中将"name:"设置为"file"。

var request = {
url: url,
method: "POST",
headers: {
"file-name": name,
"Content-Type": "application/octet-stream"
},
description: "Uploading " + name
};
var params = [
{
name: "file",
filename: filepath,
mimeType: "image/jpeg"
}
];
var task = session.multipartUpload(params, request);
task.on("responded", this.respondedHandler, this);

一旦我从 Shrine 获得成功的响应,我就串化了 JSON 并将该结果附加到我的数据模型中,稍后通过 JSON 作为我表单的一部分发送。

respondedHandler(e) {
alert("received " + e.responseCode + " code. Server sent: " + e.data);
this._dataItem.image = JSON.stringify(e.data);
}

感谢 Narendra 和 Janko-m,我没有意识到这是多么痛苦,随着我对我的问题有了更深入的了解,问题一直在变化,我一直发现了真正的问题。

注意:我已经在Shrine WIKI上记录了我的发现

从卷曲到神龛 = https://github.com/shrinerb/shrine/wiki/Uploading-through-curl

从角度 8.0 到 Shrine = https://github.com/shrinerb/shrine/wiki/Uploading-through-Angular

从 Nativescript 到 Shrine = https://github.com/shrinerb/shrine/wiki/Uploading 到 NativeScript-(Angular(

相关内容

  • 没有找到相关文章

最新更新