为啥我的应用程序无法从我的 API 读取 JSON?

Posted

技术标签:

【中文标题】为啥我的应用程序无法从我的 API 读取 JSON?【英文标题】:Why do my App cant read a JSON from my API?为什么我的应用程序无法从我的 API 读取 JSON? 【发布时间】:2017-02-17 16:35:35 【问题描述】:

我正在使用 Retrofit 2,我正在尝试从我用 Python 制作的 Web 服务请求一些数据。

实际上它会抛出“java.lang.IllegalStateException”,但是当我调用 GET 方法时,API 返回代码 200,而且我可以看到用于调试响应 JSON 的打印版本。问题在于 Call 方法,因为它总是在执行 OnFailure。

请帮忙!

这是我的(简单)Python Web 服务,api-prueba:

从烧瓶进口烧瓶,jsonify 导入json 导入 mysql.connector 导入集合 app = Flask(__name__) cnx = mysql.connector.connect(user="root", password="", host="localhost", database="gym") @app.route('/gym/api/v1.0/clases', methods=['GET']) 定义 getClass(): sql = "SELECT id, nombre, decripcion FROM clases" 光标 = cnx.cursor() cursor.execute(sql) entradas = cursor.fetchall() # Convertir la query en un array de entradas 对象列表 = [] 对于 entradas 中的行: objects_list.append(行) j = json.dumps(objects_list) 返回 j @app.route('/') 定义索引(): 返回“你好,世界!” 如果 __name__ == '__main__': 应用程序运行(调试=真)

这是我的 ApiClient:

公共类 ApiClient 私有静态 ApiService REST_CLIENT; 私有静态最终字符串 API_URL = "http://10.0.2.2:5000/gym/api/v1.0/"; //根据你的API路径改变。 静止的 setupRestClient(); 私人 ApiClient() 公共静态 ApiService get() 返回 REST_CLIENT; 私有静态无效 setupRestClient() OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); //取消注释下面的这些行以开始记录每个请求。 HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); httpClient.addInterceptor(logging); 改造改造 = new Retrofit.Builder() .baseUrl(API_URL) .addConverterFactory(GsonConverterFactory.create()) .client(httpClient.build()) 。建造(); REST_CLIENT = retrofit.create(ApiService.class);

我的 API 接口,ApiService:

公共接口 ApiService @GET("类") 调用>getClass();

这是查询 API 并获取数据的片段,ClaseFragment:

公共类 ClaseFragment 扩展 Fragment 实现 View.OnClickListener 私有列表类; 私有 ListView 列表视图; 私人按钮 btnRefresh; 公共类片段() // 必需的空公共构造函数 公共静态 ClaseFragment newInstance() ClaseFragment 片段 = 新的 ClaseFragment(); 捆绑参数 = 新捆绑(); 片段.setArguments(args); 返回片段; @覆盖 公共无效 onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); if (getArguments() != null) @覆盖 public View onCreateView(LayoutInflater inflater, ViewGroup 容器, 捆绑保存的InstanceState) // 膨胀这个片段的布局 查看 root = inflater.inflate(R.layout.fragment_clase, container, false); listView = (ListView) root.findViewById(R.id.claseList); btnRefresh = (按钮) root.findViewById(R.id.btnRefresh); btnRefresh.setOnClickListener(this); getListaClasses(); 返回根; @覆盖 公共无效 onClick(查看 v) //当按钮被点击时做你想做的事 开关 (v.getId()) 案例 R.id.btnRefresh: Log.d(getTag(), "你好"); getListaClasses(); 休息; 默认: 休息; 私人无效getListaClases() 最终 ProgressDialog 加载 = ProgressDialog.show(getActivity(), getContext().getString(R.string.loading_title), getContext().getString(R.string.loading_please_wait), 错误的, 错误的); 调用>调用 = ApiClient.get().getClasses(); call.enqueue(新回调>() @覆盖 public void onFailure(Call> call, Throwable t) Log.d("ApiService", "发生错误:" + t.getMessage()); loading.dismiss(); @覆盖 公共无效onResponse(呼叫>呼叫,响应>响应) Log.d("ApiService", "成功获取响应"); loading.dismiss(); if (response.code() == 200 && response.isSuccessful()) 类 = response.body(); 显示列表(); 别的 Log.d("APIPlug", "未找到项目"); ); //我们显示列表的方法 私人无效showList() Log.d("ApiService", "显示列表"); ClaseAdapter 适配器 = new ClaseAdapter(getActivity(), clases); listView.setAdapter(适配器); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() @覆盖 public void onItemClick(AdapterView parent, View view, int position, long id) 分类 clickedObj = (分类) parent.getItemAtPosition(position); //如果你有关于你的对象的详细活动定义在这里 /* 意图细节 = new Intent(getContext(), ActorDetail.class); detail.putExtra("actorObject", clickedObj); 开始活动(详细); */ );

这是我想要在 ListView 中显示的 Web 服务的实际响应:

 [
    [1, "halterofilia", "Profesor: XXXX YYYY. Clase de Halterofilia."],
    [2, "crossfit", "Profesor:ZZZZ TTTT. Clase de CrossFit"],
    [3, "halterofilia", "Profesor:XXXX YYYY. Clase de halterofilia"]
 ]

编辑:

来自 android Studio 的回溯:

 D/OkHttp: --> GET http://10.0.2.2:5000/gym/api/v1.0/clases http/1.1
 D/OkHttp: --> END GET
 D/OkHttp: <-- 200 OK http://10.0.2.2:5000/gym/api/v1.0/clases (8ms)
 D/OkHttp: Content-Type: text/html; charset=utf-8
 D/OkHttp: Content-Length: 192
 D/OkHttp: Server: Werkzeug/0.11.11 Python/2.7.12
 D/OkHttp: Date: Sat, 08 Oct 2016 23:19:00 GMT
 D/OkHttp: OkHttp-Sent-Millis: 1475968739892
 D/OkHttp: OkHttp-Received-Millis: 1475968739897
 D/OkHttp: [[1, "halterofilia", "Profesor: XXXX YYYY. Clase de   Halterofilia."], [2, "crossfit", "Profesor:ZZZZ TTTT. Clase de CrossFit"], [3,   "halterofilia", "Profesor:XXXX YYYY. Clase de halterofilia"]]
 D/OkHttp: <-- END HTTP (192-byte body)
 D/ApiService: Error Occured: java.lang.IllegalStateException: Expected          BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 3 path $[0]

这是来自我正在运行 Web 服务的 PyCharm:

  * Detected change in 'D:\\Proyectos\\PyCharm\\api-prueba\\api-prueba.py', reloading
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 195-275-846
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [09/Oct/2016 00:21:38] "GET /gym/api/v1.0/clases HTTP/1.1" 200 -

【问题讨论】:

【参考方案1】:

D/ApiService:发生错误:java.lang.IllegalStateException:应为 BEGIN_OBJECT,但在第 1 行第 3 列路径 $[0] 处为 BEGIN_ARRAY

从这个错误中,您可以说它与改造所期望的内容和您的 API 提供给您的内容不匹配。更具体地说,retrofit 看起来需要一个对象,但您的 API 返回一个数组。 我猜你正在尝试获取 Classes 对象的列表,而你的 API 发送了一个...数组的数组。

为此,我会尝试获得这样的 API 响应:

[
    "id": 1, "name": "halterofilia", "title": "Profesor: XXXX YYYY. Clase de Halterofilia.",
    "id": 2, "name": "crossfit", "title": "Profesor:ZZZZ TTTT. Clase de CrossFit",
    "id": 3, "name": "halterofilia", "title": "Profesor:XXXX YYYY. Clase de halterofilia"
]

(id、name 和 title 将替换为您的 db 字段的实际名称)

这是一个链接,可以指导您如何实现对 Python 代码的更改: Python converting mysql query result to json

【讨论】:

以上是关于为啥我的应用程序无法从我的 API 读取 JSON?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能从我的 Xamarin Froms 应用程序发布到我的 .net 核心 web api

在启用 CORS 的情况下,无法从我的请求标头中检索我的 x-api-key。为啥?

为啥我的 API 和 JSON 应用无法在 Android Studio 中运行

TypeError:无法读取未定义的属性(读取“国家”)

如何使用 React 从 mongoose 读取 api

在我的 laravel 应用程序中从我的 PHP API 获取 json 响应