所以,我有一个客户端移动用retrofit2做请求,并且在请求时我需要发送一个图像文件和一个json对象。像这样:
RequestBody requestJson = RequestBody.create(MediaType.parse("application/json"), new Gson().toJson(cidadao));
MultipartBody.Part fotoBody = MultipartBody.Part.createFormData("foto", file.getName(), requestFile);
MultipartBody.Part jsonBody = MultipartBody.Part.createFormData("cidadao", null, requestJson);
Service service = CallService.createService(Service.class);
Call<Void> cadastrarCidadao = service.postCidadao(UsuarioApplication.getInstance().getToken().getToken(),
jsonBody,
fotoBody);
cadastrarCidadao.enqueue(new Callback<Void>() {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
if (response.code() == 201) {
dialog.dismiss();
FragmentManager fm = getFragmentManager();
fm.popBackStack();
}
} else {
APIError error = ErrorUtils.parseError(response);
new Throwable(error.getMessage());
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
Log.e("ErrorCadastro", t.getLocalizedMessage());
Toasty.error(getContext(), "Erro na conexão").show();
}
});
服务接口:
package com.example.administrador.citycaremobile.Services;
import com.example.administrador.citycaremobile.Modelo.Cidadao;
import com.example.administrador.citycaremobile.Modelo.Login;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Part;
public interface Service {
@POST("cidadao/cadastrar")
@Multipart
Call<Void> postCidadao(@Header("X-Token") String token,
@Part MultipartBody.Part cidadao,
@Part MultipartBody.Part foto);
@PUT("cidadao/put")
Call<Boolean> putUsuario(@Header("Content-type") String content,
@Header("X-Token") String token,
@Body Cidadao cidadao);
@Headers("content-type:application/json")
@GET("auth")
Call<Token> autentication();
//Login
@POST("login")
Call<Object> login(@Header("Content-type") String content,
@Header("X-Token") String token,
@Body Login login);
}
在服务方面,有一个带有Slim框架的PHP,问题是......当我尝试使用$ request-&gt; getParam()获取json时,他们会返回一个包含所有字符的数组,其中每个character是该数组上的一个项目。
Ex:如果显示返回$ jsonParam [0],他返回给我&#34; {&#34;,我试图将所有数组解析为一个String但是不成功,尝试了implode方法,在param上尝试了json_decode但没什么用。
有服务方法:
$app -> post('/cidadao/cadastrar', function(Request $request, Response $response) use ($app){
//Container do EntityManager
$entityManager = $this -> get('em');
$json = $request -> getParam('cidadao');
try{
//Instância da entidade Login
$login = new Login();
//recuperando o parâmetro objeto login do json
$fk_login_cidadao = $json['fk_login_cidadao'];
//setando valores do objeto login
$login ->setLogin($fk_login_cidadao['login']);
$login ->setEmail($fk_login_cidadao['email']);
$login ->setSenha($fk_login_cidadao['senha']);
$login ->setStatus_login($fk_login_cidadao['status_login']);
$login ->setAsAdministrador($fk_login_cidadao['administrador']);
//salvando login
$entityManager->persist($login);
$entityManager->flush();
//buscando login recém salvo
$loginRepository = $entityManager->getRepository('App\Models\Entity\Login');
//pegando login
$loginCidadao = $loginRepository->find($login->getId_login());
//Salvar foto
$files = $request->getUploadedFiles();
$newimage = $files['foto'];
if ($newimage->getError() === UPLOAD_ERR_OK) {
$uploadFileName = $newimage->getClientFilename();
$type = $newimage->getClientMediaType();
$name = uniqid('img-' . date('d-m-y') . '-');
$name .= $newimage->getClientFilename();
// $imgs[] = array('url' => '/Photos/' . $name);
//local server
$newimage->moveTo("/home/citycare/public_html/Imgs/user/$name");#/home/citycare/Imgs/User/$name
//localdev
$photoURL = "/home/citycare/public_html/Imgs/user/$name";#/home/citycare/Imgs/User/$name
}
//Instância da entidade Cidadao
$cidadao = new Cidadao();
//setando valores do objeto cidadao
$cidadao ->setFk_login_cidadao($loginCidadao);
$cidadao->setNome($request->getParam('nome'));
$cidadao->setSexo($request->getParam('sexo'));
$cidadao ->setSobrenome($request->getParam('sobrenome'));
$cidadao ->setEstado($request->getParam('estado'));
$cidadao ->setCidade($request->getParam('cidade'));
$cidadao ->setDir_foto_usuario($request->getParam($photoURL));
$entityManager->persist($cidadao);
$entityManager->flush();
//retornando confirmação do evento completo
$return = $response->withStatus(201)->withHeader('Content-type', 'application/json');
} catch (Exception $ex){
//código e mensagem do erro
throw new Exception($ex->getMessage(), $ex->getCode());
}
return $return;
});
图像处理正常。
HTTP请求:
10-14 03:35:38.772 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --> POST http://servico.projetocitycare.com.br/cidadao/cadastrar http/1.1
10-14 03:35:38.773 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Type: multipart/form-data; boundary=58c96b8f-a56e-4b42-8052-10d48c583cc4
10-14 03:35:38.776 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Length: 69178
10-14 03:35:38.777 19151-9871/com.example.administrador.citycaremobile D/OkHttp: X-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoicm9vdCIsInNlbmhhIjoiY2FyZWNpdHkiLCJleHAiOjE1MDc5NjMwOTUsImlwIjoiMTc3LjM3LjIyOC4xNDIifQ.ePeHn_YgmRfach6B1v4JC75147ixRwrjdoUvEjpPKRQ
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --58c96b8f-a56e-4b42-8052-10d48c583cc4
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Disposition: form-data; name="cidadao"
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Type: application/json; charset=utf-8
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Length: 239
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: {"cidade":"Alto Rio Novo","estado":"Espírito Santo","fk_login_cidadao":{"administrador":false,"email":"ekekejj@mks.xkm","login":"kddjsjn","senha":"jskeieej","status_login":true},"nome":"neenenem","sexo":"Masculino","sobrenome":"memekekk"}
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --58c96b8f-a56e-4b42-8052-10d48c583cc4
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Disposition: form-data; name="foto"; filename="cropped83912673.jpg"
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Type: multipart/form-data
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Length: 68558
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: ������JFIF����������������C��
10-14 03:35:38.800 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --58c96b8f-a56e-4b42-8052-10d48c583cc4--
10-14 03:35:38.800 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --> END POST (69178-byte body)
HTTP响应:
10-14 03:35:39.675 19151-9871/com.example.administrador.citycaremobile D/OkHttp: <-- 500 Internal Server Error http://servico.projetocitycare.com.br/cidadao/cadastrar (874ms)
10-14 03:35:39.676 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Server: nginx
10-14 03:35:39.676 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Date: Sat, 14 Oct 2017 06:35:39 GMT
10-14 03:35:39.676 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Type: application/json;charset=utf-8
10-14 03:35:39.677 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Transfer-Encoding: chunked
10-14 03:35:39.677 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Connection: keep-alive
10-14 03:35:39.678 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Upgrade: h2,h2c
10-14 03:35:39.685 19151-9871/com.example.administrador.citycaremobile D/OkHttp: {"message":"An exception occurred while executing 'INSERT INTO login (email, login, senha, status_login, administrador) VALUES (?, ?, ?, ?, ?)' with params [\"{\", \"{\", \"ew==\", \"{\", \"{\"]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '{' for key 'UNIQ_AA08CB10E7927C74'"}
10-14 03:35:39.686 19151-9871/com.example.administrador.citycaremobile D/OkHttp: <-- END HTTP (310-byte body)
杰森发的是这样的:
{"cidade":"Brasília",
"estado":"Distrito Federal",
"fk_login_cidadao":{ "administrador":false,
"email":"b@b.com",
"login":"jhon",
"senha":"182873728192",
"status_login":true},
"nome":"Jhon",
"sexo":"Masculino",
"sobrenome":"James"}
答案 0 :(得分:0)
您的请求正文大部分都是合理的,除此之外:Content-Transfer-Encoding: binary
我不明白为什么retrofit2会将其添加到form-data
。但是,我并不认为这是您遇到的错误。
我认为PHP没有正确解析form-data
因为这个额外的位。但后来我意识到你正在解析JSON并将其作为数组访问。您的json字符串是一个对象,将由PHP JSON解码器解释。
总而言之,您应该像这样访问数据(json)对象的值:$json->fk_login_cidadao
而不是这样:$json['fk_login_cidadao']
。这也适用于其余的价值和密钥对。
如果您想测试我的理论,只需将参数$request -> getParam('cidadao')
的内容记录或写入文件。
答案 1 :(得分:0)
所以,经过多次尝试,在$ json上使用var_dump()我看到请求没有被框架解码,我不知道为什么,所以我需要手动解码并使用Object而不是数组。最后API端代码保持这样:
$app ->post('/cidadao/cadastrar', function(Request $request, Response $response) use ($app){
//Container do EntityManager
$entityManager = $this -> get('em');
$json = $request->getParam('cidadao');
$json = json_decode($json);
try{
//Instância da entidade Login
$login = new Login();
//recuperando o parâmetro objeto login do json
$fk_login_cidadao = $json -> fk_login_cidadao;
//setando valores do objeto login
$login ->setLogin($fk_login_cidadao -> login);
$login ->setEmail($fk_login_cidadao -> email);
$login ->setSenha($fk_login_cidadao -> senha);
$login ->setStatus_login($fk_login_cidadao -> status_login);
$login ->setAsAdministrador($fk_login_cidadao -> administrador);
//salvando login
$entityManager->persist($login);
$entityManager->flush();
//buscando login recém salvo
$loginRepository = $entityManager->getRepository('App\Models\Entity\Login');
//pegando login
$loginCidadao = $loginRepository->find($login->getId_login());
//Salvar foto
$files = $request->getUploadedFiles();
$newimage = $files['foto'];
if ($newimage->getError() === UPLOAD_ERR_OK) {
$uploadFileName = $newimage->getClientFilename();
$type = $newimage->getClientMediaType();
$name = uniqid('img-' . date('d-m-y') . '-');
$name .= $newimage->getClientFilename();
// $imgs[] = array('url' => '/Photos/' . $name);
//local server
$newimage->moveTo("/home/citycare//imgs/$name");#/home/citycare/Imgs/User/$name
//localdev
$photoURL = "/home/citycare//imgs/$name";#/home/citycare/Imgs/User/$name
}
//Instância da entidade Cidadao
$cidadao = new Cidadao();
//setando valores do objeto cidadao
$cidadao ->setFk_login_cidadao($loginCidadao);
$cidadao->setNome($json -> nome);
$cidadao->setSexo($json -> sexo);
$cidadao ->setSobrenome($json -> sobrenome);
$cidadao ->setEstado($json -> estado);
$cidadao ->setCidade($json -> cidade);
$cidadao ->setDir_foto_usuario($photoURL);
$entityManager->persist($cidadao);
$entityManager->flush();
//retornando confirmação do evento completo
$return = $response->withStatus(201)->withHeader('Content-type', 'application/json');
} catch (Exception $ex){
//código e mensagem do erro
throw new Exception($ex->getMessage(), $ex->getCode());
}
return $return;
});