凌峰创科服务平台

Android与PHP服务器交互如何实现?

目录

  1. 核心原理:HTTP 请求/响应模型
  2. 技术选型
    • Android 端:网络库选择
    • 服务器端:PHP 框架选择
  3. 交互流程详解
  4. 代码实战
    • Android 端 (Kotlin + Retrofit)
    • PHP 服务器端 (原生 PHP + PDO)
  5. 数据格式:JSON
  6. 安全最佳实践 (至关重要)
  7. 常见问题与解决方案

核心原理:HTTP 请求/响应模型

Android 和 PHP 服务器之间的所有通信都基于 HTTP (Hypertext Transfer Protocol) 协议,这个过程可以简化为以下几个步骤:

Android与PHP服务器交互如何实现?-图1
(图片来源网络,侵删)
  1. Android 客户端:当应用需要数据(获取用户信息)或执行操作(发布一条新动态)时,它会构建一个 HTTP 请求

    • 请求方法GET (获取数据), POST (提交数据), PUT (更新数据), DELETE (删除数据)。
    • 请求头:包含元数据,如 Content-Type (告诉服务器发送的是什么格式的数据,如 application/json)。
    • 请求体:对于 POSTPUT 请求,这里包含实际要发送的数据(如用户名、密码)。
  2. 网络传输:这个 HTTP 请求通过互联网(通常是 Wi-Fi 或移动数据)发送到你配置好的 PHP 服务器上的一个特定地址(URL)。

  3. PHP 服务器端

    • 接收请求:PHP 脚本(login.php)运行在服务器上,接收来自 Android 客户端的 HTTP 请求。
    • 处理逻辑:PHP 脚本解析请求头和请求体,然后执行相应的业务逻辑,连接数据库,验证用户名和密码。
    • 生成响应:根据处理结果,PHP 脚本构建一个 HTTP 响应
      • 响应状态码:如 200 OK (成功), 404 Not Found (资源未找到), 401 Unauthorized (未授权)。
      • 响应头:如 Content-Type: application/json
      • 响应体:包含服务器返回给客户端的数据,通常是 JSON 格式的字符串。
  4. Android 客户端:接收到 PHP 服务器的 HTTP 响应后,应用会解析响应体(JSON 数据),并根据内容更新 UI(登录成功则跳转到主界面,失败则显示错误提示)。

    Android与PHP服务器交互如何实现?-图2
    (图片来源网络,侵删)

简而言之:Android 发送请求 -> PHP 接收并处理 -> PHP 发送响应 -> Android 接收并解析。


技术选型

直接使用 HttpURLConnection 是可以的,但非常繁琐,现代开发中,我们更推荐使用封装好的库。

Android 端:网络库选择

库名 特点 推荐度
Retrofit 强烈推荐,由 Square 公司开发,它将 HTTP API 转换为 Java/Kotlin 接口,使用注解定义 API,支持 Gson/Moshi 等自动转换 JSON,代码极其简洁、类型安全、易于维护。 ⭐⭐⭐⭐⭐
OkHttp Retrofit 的底层依赖,它是一个高效的 HTTP 客户端,负责处理连接、缓存、超时等,通常我们直接使用 Retrofit,它会自动使用 OkHttp。 ⭐⭐⭐⭐⭐
Volley Google 推出的库,优点是请求队列管理、缓存机制简单,但对于复杂的网络请求和文件上传,Retrofit 更灵活。 ⭐⭐⭐
HttpURLConnection Android SDK 自带,功能齐全,但代码冗长,需要手动处理线程和解析,不推荐用于新项目。 ⭐⭐

对于新项目,首选 Retrofit + OkHttp + Kotlinx SerializationGson 的组合。

服务器端:PHP 框架选择

框架 特点 推荐度
原生 PHP 灵活,轻量级,适合小型项目、学习或 API 开发,需要自己处理数据库连接、路由等。 ⭐⭐⭐⭐
Laravel 强烈推荐,功能强大、优雅的 PHP 框架,拥有完善的路由系统、Eloquent ORM(数据库操作)、强大的安全防护机制(如 CSRF 防护),开发效率极高。 ⭐⭐⭐⭐⭐
Slim 一个专注于快速开发 RESTful API 的微框架,非常轻量,配置简单,是构建 API 的理想选择。 ⭐⭐⭐⭐

如果只是简单的 API,原生 PHP + PDO 就足够了,如果项目规模较大或追求开发效率,Laravel 是不二之选。

Android与PHP服务器交互如何实现?-图3
(图片来源网络,侵删)

交互流程详解

以一个典型的 用户登录 功能为例:

  1. Android 端

    • 用户在输入框中输入用户名和密码,点击“登录”按钮。
    • Retrofit 将用户名和密码封装成一个 JSON 对象,如 {"username": "john", "password": "123456"}
    • Retrofit 发送一个 POST 请求到 https://yourdomain.com/api/login,并将 JSON 数据放在请求体中。
  2. PHP 服务器端

    • 服务器接收到请求,路由将请求指向 login.php 文件。
    • login.php 读取请求体,解析出 usernamepassword
    • 使用 PDO (PHP Data Objects) 连接 MySQL 数据库。
    • 执行一条 SELECT 查询,检查数据库中是否存在该用户名和密码(注意:密码应该是哈希值,而不是明文!)。
    • 如果找到匹配的用户:
      • 生成一个响应体,{"status": "success", "user_id": 123, "message": "Login successful"}
      • 设置 HTTP 状态码为 200 OK
    • 如果没有找到:
      • 生成一个响应体,{"status": "error", "message": "Invalid username or password"}
      • 设置 HTTP 状态码为 401 Unauthorized
    • PHP 将这个 JSON 响应发送回 Android 客户端。
  3. Android 端

    • Retrofit 接收到响应。
    • 它会自动将 JSON 字符串解析成一个 Kotlin 数据类(如 LoginResponse)。
    • 在回调接口中,我们检查 LoginResponse.status 的值。
    • 如果是 "success",则跳转到主界面,并保存用户信息(如 user_id)。
    • 如果是 "error",则在屏幕上显示 LoginResponse.message 的内容。

代码实战

我们将使用 Android (Kotlin + Retrofit)PHP (原生 + PDO) 来实现一个简单的用户注册功能。

Android 端 (Kotlin + Retrofit)

添加依赖 (build.gradle.ktsbuild.gradle)

// build.gradle (Module :app)
dependencies {
    // Retrofit & OkHttp
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0") // 用于 JSON 转换
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.3") // 用于打印日志
    // Kotlin Coroutines (用于异步处理)
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
}

添加网络权限 (AndroidManifest.xml)

<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application ...>
        ...
    </application>
</manifest>

定义数据模型

// 请求的数据模型
data class RegisterRequest(
    val username: String,
    val email: String,
    val password: String
)
// 响应的数据模型
data class RegisterResponse(
    val status: String,
    val message: String
)

创建 Retrofit 实例和 API 接口

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.POST
// 定义 API 接口
interface ApiService {
    @POST("api/register.php") // 你的 PHP 文件路径
    suspend fun register(@Body request: RegisterRequest): RegisterResponse
}
// 创建 Retrofit 单例
object RetrofitClient {
    private const val BASE_URL = "https://yourdomain.com/" // 你的服务器地址
    val instance: ApiService by lazy {
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        retrofit.create(ApiService::class.java)
    }
}

在 ViewModel 或 Activity 中调用

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class RegisterViewModel : ViewModel() {
    fun registerUser(username: String, email: String, password: String) {
        viewModelScope.launch {
            try {
                val request = RegisterRequest(username, email, password)
                val response = RetrofitClient.instance.register(request)
                if (response.status == "success") {
                    // 注册成功,处理UI逻辑
                    Log.d("Register", "Success: ${response.message}")
                } else {
                    // 注册失败,处理UI逻辑
                    Log.e("Register", "Error: ${response.message}")
                }
            } catch (e: Exception) {
                // 网络错误等异常
                Log.e("Register", "Exception: ${e.message}")
            }
        }
    }
}

PHP 服务器端 (原生 PHP + PDO)

数据库准备

假设你有一个 users 表:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

api/register.php

<?php
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *"); // 允许所有来源的请求,生产环境应限制为你的域名
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// 1. 获取并解码请求体
$data = json_decode(file_get_contents("php://input"));
// 2. 验证数据
if (!isset($data->username) || !isset($data->email) || !isset($data->password)) {
    http_response_code(400); // Bad Request
    echo json_encode(["status" => "error", "message" => "Missing required fields."]);
    exit();
}
$username = $data->username;
$email = $data->email;
$password = $data->password;
// 3. 密码哈希 (非常重要!)
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
// 4. 连接数据库 (使用 PDO)
$servername = "localhost";
$dbname = "your_database_name";
$dbusername = "your_db_username";
$dbpassword = "your_db_password";
try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $dbusername, $dbpassword);
    // 设置 PDO 错误模式为异常
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    // 5. 准备 SQL 语句 (使用预处理语句防止 SQL 注入)
    $sql = "INSERT INTO users (username, email, password) VALUES (:username, :email, :password)";
    $stmt = $conn->prepare($sql);
    // 绑定参数
    $stmt->bindParam(':username', $username);
    $stmt->bindParam(':email', $email);
    $stmt->bindParam(':password', $hashed_password);
    // 执行语句
    if ($stmt->execute()) {
        // 注册成功
        http_response_code(201); // Created
        echo json_encode(["status" => "success", "message" => "User registered successfully."]);
    } else {
        // 注册失败 (例如用户名或邮箱已存在)
        http_response_code(500); // Internal Server Error
        echo json_encode(["status" => "error", "message" => "Registration failed."]);
    }
} catch(PDOException $e) {
    // 数据库错误
    http_response_code(500);
    echo json_encode(["status" => "error", "message" => "Database error: " . $e->getMessage()]);
}
// 关闭连接
$conn = null;
?>

数据格式:JSON

JSON (JavaScript Object Notation) 是目前最主流的数据交换格式,它轻量、易于人阅读和编写,也易于机器解析和生成。

  • 结构:键值对的集合,类似于 Java/Kotlin 的 Map 或对象。
  • 示例
    {
      "status": "success",
      "user_id": 101,
      "profile": {
        "username": "android_dev",
        "email": "dev@example.com"
      },
      "posts": [
        {"id": 1, "title": "Hello World"},
        {"id": 2, "title": "My Second Post"}
      ]
    }

Retrofit 和 Gson/Moshi 可以完美地将 JSON 字符串自动映射到 Kotlin 的数据类,反之亦然,极大地简化了开发。


安全最佳实践 (至关重要)

不安全的通信会导致用户数据泄露、账户被盗等严重问题。

  1. HTTPS (必须使用)

    • 是什么:HTTP over SSL/TLS,它在 HTTP 和 TCP 之间加了一层加密,所有传输的数据都是加密的。
    • 为什么:防止中间人攻击,防止用户名、密码、个人敏感信息在传输过程中被窃听。
    • 怎么做:在你的服务器上配置 SSL 证书(如 Let's Encrypt 提供的免费证书),在 AndroidManifest.xml 中配置 networkSecurityConfig 来允许 HTTPS。
  2. 防止 SQL 注入

    • 是什么:攻击者通过在输入字段中注入恶意的 SQL 代码来操纵数据库。
    • 怎么做永远不要将用户输入直接拼接到 SQL 查询中。始终使用预处理语句,就像上面 PHP 代码示例中的 prepare()bindParam()
  3. 密码安全

    • 是什么:绝不能以明文存储密码。
    • 怎么做:在存储密码之前,使用 password_hash() 函数进行哈希处理,在验证密码时,使用 password_verify() 函数。不要自己实现哈希算法
  4. 输入验证

    • 是什么:验证来自客户端的输入是否符合预期的格式和范围。
    • 怎么做:在 Android 端和 PHP 服务器端都要进行验证,检查邮箱格式、用户名长度、密码强度等,客户端验证是为了提升用户体验,服务器端验证是安全性的最后一道防线。
  5. API 密钥和认证

    • 是什么:对于需要保护的 API,你需要一种方式来验证请求是否来自合法的 Android 应用。
    • 怎么做
      • API Key:在 Android 应用中硬编码一个唯一的密钥,并在每个请求中发送,简单但容易被反编译获取。
      • Token (如 JWT - JSON Web Token):更安全的方式,用户登录成功后,服务器生成一个包含用户信息的加密 Token 返回给客户端,客户端后续的请求都在请求头中携带这个 Token,服务器验证 Token 的有效性即可。

常见问题与解决方案

  • 问题:Android 10+ (API 29+) 上 HTTP 请求失败。

    • 原因:Android 9 开始默认禁止使用非加密的 HTTP 连接。
    • 解决方案:强制使用 HTTPS,如果必须使用 HTTP(仅限本地开发),需要在 AndroidManifest.xml 中配置 usesCleartextTraffictrue,并配置 networkSecurityConfig
  • 问题:android.os.NetworkOnMainThreadException

    • 原因:在主线程(UI 线程)上执行了网络操作,这会阻塞 UI 并可能导致应用“无响应”(ANR)。
    • 解决方案永远不要在主线程上进行网络请求,使用 AsyncTask (已过时)、Thread + Handler,或者更现代的 Kotlin CoroutinesRxJava,Retrofit 本身就支持在协程中调用,非常方便。
  • 问题:PHP 服务器返回 404 Not Found

    • 原因:URL 路径错误,或者 PHP 文件不在指定位置。
    • 解决方案:仔细检查 Retrofit 中的 @POST("api/register.php") 中的路径是否与服务器上的文件路径完全匹配。
  • 问题:JSON 解析失败。

    • 原因:服务器返回的 JSON 格式与 Kotlin 数据类的结构不匹配,或者服务器返回了 HTML 错误页面(如 500 错误时的 Nginx/Apache 默认页面)。
    • 解决方案
      1. 使用 OkHttp 的 Interceptor 打印服务器返回的原始响应内容,看看到底是什么。
      2. 使用在线 JSON 校验工具检查你的 JSON 是否格式正确。
      3. 确保 Kotlin 数据类的字段名和 JSON 的键名完全一致(或使用 @SerializedName("json_key") 注解)。

希望这份详细的指南能帮助你顺利实现 Android 与 PHP 服务器的交互!祝你编码愉快!

分享:
扫描分享到社交APP
上一篇
下一篇