当前位置: 首页 > news >正文

Android学习之实战登录注册能力

        我们可以从本地 Token 存储、时效管理、服务端通知联动、定时器优化四个维度深入展开

一、本地 Token 存储设计(基于 SharedPreferences)

1. 存储结构优化(包含时效性字段)
// 定义存储类(封装SharedPreferences操作)
public class TokenManager {private static final String PREF_NAME = "AuthPrefs";private static final String KEY_TOKEN = "access_token";private static final String KEY_TOKEN_EXPIRE_TIME = "token_expire_time"; // 时间戳(毫秒)private static final String KEY_REFRESH_TOKEN = "refresh_token"; // 用于自动续期private final SharedPreferences sp;public TokenManager(Context context) {// 推荐使用EncryptedSharedPreferences进行加密存储(需AndroidX Security库)sp = EncryptedSharedPreferences.create(context,PREF_NAME,MasterKey.getInstance(context, MasterKey.DEFAULT_KEY_SCHEME),EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM);}// 保存Token及有效期public void saveToken(String accessToken, String refreshToken, long expireTimeMillis) {sp.edit().putString(KEY_TOKEN, accessToken).putString(KEY_REFRESH_TOKEN, refreshToken).putLong(KEY_TOKEN_EXPIRE_TIME, expireTimeMillis).apply(); // 异步提交,避免ANR}// 获取Token(自动检查是否过期)public String getValidToken() {String token = sp.getString(KEY_TOKEN, null);long expireTime = sp.getLong(KEY_TOKEN_EXPIRE_TIME, 0);if (token != null && System.currentTimeMillis() < expireTime) {return token;}return null; // 过期或未存储}// 清除Token(密码修改/主动退出时调用)public void clearToken() {sp.edit().clear().apply();}
}
2. 关键设计点:
  • 加密存储:使用 AndroidX Security 库的EncryptedSharedPreferences,防止 Token 被明文读取(比普通 SP 更安全)。
  • 双 Token 机制accessToken(短有效期,如 1 小时)+ refreshToken(长有效期,如 7 天),自动续期时用refreshToken获取新accessToken,避免频繁登录。
  • 时间戳校验:通过expireTimeMillis判断 Token 是否过期(当前时间 > 过期时间戳则失效)。

二、Token 时效处理:手动 vs 自动

1. 网络请求前的预处理(统一拦截器)
// OkHttp拦截器,自动注入Token并处理过期
public class AuthInterceptor implements Interceptor {private final TokenManager tokenManager;public AuthInterceptor(TokenManager tokenManager) {this.tokenManager = tokenManager;}@Overridepublic Response intercept(Chain chain) throws IOException {Request originalRequest = chain.request();String token = tokenManager.getValidToken();// 注入Token到请求头Request authenticatedRequest = originalRequest.newBuilder().header("Authorization", "Bearer " + token).build();Response response = chain.proceed(authenticatedRequest);// 处理401/403状态码(Token失效)if (response.code() == 401) {// 自动处理:尝试用RefreshToken获取新AccessTokenif (handleTokenExpireAutomatically()) {// 重试原请求String newToken = tokenManager.getValidToken();authenticatedRequest = originalRequest.newBuilder().header("Authorization", "Bearer " + newToken).build();return chain.proceed(authenticatedRequest);} else {// 手动处理:跳转到登录页(需通过Activity上下文或EventBus通知UI)EventBus.getDefault().post(new TokenExpiredEvent());}}return response;}private boolean handleTokenExpireAutomatically() {String refreshToken = tokenManager.getRefreshToken(); // 自定义方法获取RefreshTokenif (refreshToken != null) {try {// 调用服务端Refresh APIRefreshTokenResponse response = RetrofitClient.getInstance().getAuthService().refreshToken(refreshToken).execute().body();if (response != null && response.isSuccess()) {tokenManager.saveToken(response.getAccessToken(),response.getRefreshToken(), // 可能返回新的RefreshToken(按需更新)response.getExpireTimeMillis());return true; // 续期成功}} catch (Exception e) {e.printStackTrace();}}return false; // 续期失败,需手动登录}
}
2. 手动处理逻辑(UI 层响应)
// 在BaseActivity或全局EventBus监听Token失效事件
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EventBus.getDefault().register(this);}@Subscribepublic void onTokenExpired(TokenExpiredEvent event) {// 清除本地Token并跳转登录tokenManager.clearToken();Intent intent = new Intent(this, LoginActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);}@Overrideprotected void onDestroy() {super.onDestroy();EventBus.getDefault().unregister(this);}
}

三、服务端密码修改后的跨端通知(核心同步机制)

1. 服务端主动通知客户端(基于 WebSocket/MQTT)
// 客户端WebSocket监听(示例,使用OkHttp WebSocket)
public class AuthWebSocketClient {private WebSocket webSocket;public void connect() {Request request = new Request.Builder().url("ws://your-server/ws/auth?token=" + tokenManager.getValidToken()).build();OkHttpClient client = new OkHttpClient();client.newWebSocket(request, new WebSocketListener() {@Overridepublic void onMessage(WebSocket webSocket, String text) {// 解析通知内容(如:{"type":"password_changed"})handleServerNotification(text);}private void handleServerNotification(String message) {try {JSONObject json = new JSONObject(message);if ("password_changed".equals(json.getString("type"))) {// 密码已修改,主动验证Token有效性(服务端可能已使旧Token失效)checkTokenValidityAndLogout();}} catch (JSONException e) {e.printStackTrace();}}private void checkTokenValidityAndLogout() {// 调用一个轻量API验证Token(如/me/check-token)RetrofitClient.getInstance().getAuthService().checkTokenValidity().enqueue(new Callback<Boolean>() {@Overridepublic void onResponse(Call<Boolean> call, Response<Boolean> response) {if (response.body() != null && !response.body()) {// Token已失效,清除本地数据并跳转登录tokenManager.clearToken();runOnUiThread(() -> {Intent intent = new Intent(context, LoginActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);startActivity(intent);});}}@Overridepublic void onFailure(Call<Boolean> call, Throwable t) {// 网络失败,默认认为Token可能失效,安全起见跳转登录tokenManager.clearToken();// ... 跳转逻辑 ...}});}});}
}
2. 通知机制核心逻辑:
  • 触发时机:用户在任意端修改密码时,服务端遍历该用户所有设备的 WebSocket 连接,发送password_changed通知(需设备 ID 与 WebSocket 连接绑定)。
  • 二次验证:客户端收到通知后,不直接清除 Token,而是通过轻量 API(如/check-token)验证当前 Token 是否有效(服务端此时已使旧 Token 失效,返回 401),确保通知不是伪造的。
  • 兼容性:对于不支持 WebSocket 的旧设备,可通过下次网络请求时被动触发失效(如拦截器检测到 401 后跳转登录)。

四、定时器优化:替代方案与最佳实践

1. 避免使用java.util.Timer(推荐 WorkManager)
// 使用WorkManager实现定时Token检查(Android Jetpack组件)
public class TokenRefreshWorker extends Worker {private static final String WORK_NAME = "Token_Refresh_Worker";public TokenRefreshWorker(@NonNull Context context, @NonNull WorkerParameters params) {super(context, params);}@NonNull@Overridepublic Result doWork() {// 检查Token是否即将过期(如提前5分钟刷新)long expireTime = tokenManager.getTokenExpireTime(); // 自定义方法获取过期时间戳long currentTime = System.currentTimeMillis();if (expireTime - currentTime < 5 * 60 * 1000) { // 剩余5分钟handleTokenExpireAutomatically(); // 复用拦截器中的自动续期逻辑}return Result.success();}// 调度Worker(在登录成功后调用)public static void scheduleTokenRefresh(Context context) {PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(TokenRefreshWorker.class,15, // 检查间隔(建议不低于15分钟,避免耗电)TimeUnit.MINUTES).setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()).build();WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_NAME,ExistingPeriodicWorkPolicy.KEEP,workRequest);}
}
2. 为什么不用Timer
  • 后台限制:Android 8.0 + 限制后台定时器精度,Timer.schedule()可能延迟执行,而 WorkManager 会根据系统状态(如省电模式、充电状态)智能调度,更省电。
  • 进程重启:WorkManager 支持设备重启后自动恢复任务,而Timer在进程被杀后失效。
  • 兼容性:WorkManager 是 Google 推荐的后台任务方案,覆盖从 API 14 到最新版本。

五、边缘场景处理与安全增强

1. 多端并发修改密码的冲突处理
  • 服务端在密码修改接口(/password/update)中,每次修改后生成一个全局token_version(存入用户表),并随 Token 返回给客户端。
  • 客户端每次网络请求携带token_version,服务端发现请求中的版本号小于数据库中的最新版本时,直接返回 401(即使 Token 未过期,也视为失效)。
2. 防止定时器被恶意利用
  • WorkManagerConstraints中添加网络限制(仅 Wi-Fi 时执行),避免移动数据下频繁请求。
  • 定时器检查时,仅执行自动续期逻辑,不处理跳转登录等 UI 操作(UI 逻辑通过 EventBus 在主线程处理)。
3. 日志与调试
  • 记录 Token 的存储、更新、过期、清除操作到本地日志(如Log.d("TokenManager", "Token expired, trying to refresh...")),方便排查问题。
  • 在调试阶段,提供 “强制 Token 过期” 的测试按钮,模拟失效场景。

六、总结:从本地到云端的完整链路

  1. 本地存储:使用加密 SP 存储 Token 及过期时间,确保安全性和时效性校验。
  2. 网络层拦截:通过 OkHttp 拦截器统一处理 Token 注入和过期重试,分离业务逻辑。
  3. 服务端通知:基于 WebSocket 实现实时密码修改通知,结合二次验证接口确保通知真实性。
  4. 后台任务:用 WorkManager 替代传统定时器,优化耗电并保证可靠性。

扩展追问

一、为什么选择 MMKV 替代 SharedPreferences?

1. MMKV 的核心优势(面试官必问):
  • 高性能:基于 mmap 内存映射技术,读写速度远优于 SharedPreferences(尤其频繁读写场景),避免 ANR。
  • 多进程安全:原生支持多进程访问,无需额外处理并发冲突(SharedPreferences 多进程需手动加锁)。
  • 易用性:API 与 SharedPreferences 类似,但支持更多数据类型(如 boolean 数组、自定义对象需序列化),且提供批量操作。
  • 体积轻量:腾讯开源,稳定性高,适合移动端大规模使用。
2. 适用场景匹配
  • Token 和时间戳需高频读写(如每次网络请求前校验),MMKV 的高性能能显著提升效率。
  • 若 App 存在多进程(如后台 Service、推送进程),MMKV 可保证数据一致性。

二、MMKV 实现 Token 存储与时效性管理

1. 初始化 MMKV(在 Application 中):
// 基础初始化(默认存储路径:/data/data/包名/documents/MMKV/)
MMKV.initialize(this);// 可选:加密(如 AES,适合敏感数据)
MMKV.defaultMMKV().setEncryptKey("自定义加密密钥"); 
2. 存储 Token 与时间戳
// 保存 Token 及过期时间(例:Token 有效期 1 小时)
MMKV mmkv = MMKV.defaultMMKV();
mmkv.putString("token", response.getToken()); 
mmkv.putLong("token_expire_time", System.currentTimeMillis() + 3600 * 1000); // 时间戳(毫秒)
3. 获取 Token 并校验时效性
public String getValidToken() {MMKV mmkv = MMKV.defaultMMKV();String token = mmkv.getString("token", "");long expireTime = mmkv.getLong("token_expire_time", 0);if (TextUtils.isEmpty(token) || System.currentTimeMillis() >= expireTime) {return null; // Token 无效或过期}return token;
}
面试扩展
1. 本地存储层:安全与性能的平衡

面试高频考点

  • 如何设计安全的 Token 存储方案?(涉及加密、防窃取)
  • 对比 SharedPreferences、MMKV、数据库等存储方案的优劣。

解决方案

  • 加密存储:使用EncryptedSharedPreferences或 MMKV 的 AES 加密功能,防止 Token 被明文读取。
    // MMKV加密初始化(需配置密钥)
    MMKV mmkv = MMKV.mmkvWithID("auth", MMKV.MULTI_PROCESS, new AESKeyProvider("your_secure_key"));
    
  • 双 Token 机制accessToken(短有效期)+ refreshToken(长有效期),减少用户登录频率。
    // 存储结构
    mmkv.putString("access_token", token);
    mmkv.putString("refresh_token", refreshToken);
    mmkv.putLong("expire_time", System.currentTimeMillis() + 3600 * 1000); // 1小时有效期
    

  • 多进程支持:MMKV 原生支持多进程访问,避免 SharedPreferences 的并发冲突。

 

三、Token 过期处理(手动 / 自动)

1. 自动续期(重点:避免频繁网络请求)
  • 提前续期:在 Token 过期前(如剩余 10 分钟)触发续期,而非过期后再处理,减少用户无感知中断。
private void checkTokenExpire() {long expireTime = MMKV.defaultMMKV().getLong("token_expire_time", 0);if (expireTime - System.currentTimeMillis() < 10 * 60 * 1000) { // 剩余 10 分钟refreshToken(); // 调用接口续期}
}
  • 续期逻辑
    private void refreshToken() {// 携带旧 Token 申请新 Tokenapi.refreshToken(oldToken).enqueue(new Callback<TokenResponse>() {@Overridepublic void onResponse(Call<TokenResponse> call, Response<TokenResponse> response) {if (response.isSuccessful()) {saveNewToken(response.body()); // 保存新 Token 及时间戳} else {// 续期失败,触发手动处理(跳转登录)navigateToLogin();}}});
    }
    
2. 手动处理(用户感知场景)
  • 当网络请求返回 401 Unauthorized(Token 无效)时,清除本地数据并跳转登录:
// 在 BaseUrlInterceptor 或全局错误处理中
if (code == 401) {MMKV.defaultMMKV().removeValueForKey("token"); // 清除旧 TokenMMKV.defaultMMKV().removeValueForKey("token_expire_time");// 跳转登录,需处理 Activity 栈(如使用 Application 单例标记登录状态)Intent intent = new Intent(context, LoginActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(intent);
}

面试扩展 

  • 如果 Token 被窃取,如何防止中间人攻击?
    • A
      1. HTTPS 传输:所有 Token 交互使用 HTTPS,防止传输中被截获。
      2. 时间戳校验:每次请求携带时间戳,服务端验证时间差(如 5 分钟内有效)。
      3. 签名机制:将 Token、时间戳、请求参数组合后用 HMAC-SHA256 签名,防止参数篡改。
      // 客户端签名示例
      String sign = HmacSHA256Utils.hmacSHA256(token + timestamp + params, secretKey);
      
2. 网络层:Token 自动续期与失效处理

面试高频考点

  • 如何处理 Token 过期?(自动续期 vs 手动跳转)
  • 如何设计网络拦截器统一处理 Token?

解决方案

  • OkHttp 拦截器:自动注入 Token 并处理 401 错误。
    public class AuthInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request().newBuilder().header("Authorization", "Bearer " + mmkv.getString("access_token")).build();Response response = chain.proceed(request);if (response.code() == 401) {// 自动续期String newToken = refreshToken();if (newToken != null) {request = request.newBuilder().header("Authorization", "Bearer " + newToken).build();return chain.proceed(request);}// 手动处理:跳转登录navigateToLogin();}return response;}
    }
    

  • 自动续期策略:在 Token 过期前 10 分钟触发续期,减少用户感知。
    private void checkTokenExpire() {long expireTime = mmkv.getLong("expire_time");if (expireTime - System.currentTimeMillis() < 10 * 60 * 1000) {refreshToken();}
    }
    

四、多端密码修改后的 Token 失效同步(核心逻辑)

1. 服务端主动通知客户端(需结合推送或长连接)
  • 当用户在另一端修改密码时,服务端需向所有在线客户端发送 Token 失效通知(如通过 WebSocket、FCM 推送)。
  • 客户端收到通知后,立即校验本地 Token 并强制失效:
    // 推送接收逻辑示例
    private void handleTokenInvalidate() {MMKV mmkv = MMKV.defaultMMKV();// 清除本地 Token(即使未过期也强制失效)mmkv.removeValueForKey("token");mmkv.removeValueForKey("token_expire_time");// 跳转登录(需处理当前页面栈)navigateToLoginAndFinishAll();
    }
    
2. 跨设备 / 端的最终一致性
  • 若未收到推送(如客户端离线),下次启动或网络请求时,通过 getValidToken() 发现 Token 无效,仍会跳转登录,保证最终一致性。

面试追问

多端同步:服务端通知与本地校验

面试高频考点

  • 如何实现一端修改密码,其他端自动失效?
  • 如何处理服务端主动通知客户端?

解决方案

  • WebSocket 长连接:接收服务端密码修改通知。
    WebSocketClient webSocket = new WebSocketClient(Uri.parse("ws://your-server/ws")) {@Overridepublic void onMessage(String message) {if ("password_changed".equals(message)) {// 清除本地Token并跳转登录mmkv.clearAll();navigateToLogin();}}
    };
    
  • 本地校验增强:每次请求时携带token_version,服务端检测版本号是否一致。
    // 服务端返回token时包含版本号
    mmkv.putInt("token_version", response.getVersion());// 客户端请求时携带版本号
    request = request.newBuilder().header("X-Token-Version", mmkv.getInt("token_version")).build();
    

面试官追问

  • Q:如果客户端未收到 WebSocket 通知(如离线),如何保证最终一致性?
    • A
      1. 下次启动时校验:App 启动后主动调用/check-token接口验证有效性。
      2. 定时任务:使用 WorkManager 每小时执行一次 Token 有效性检查。

五、定时器优化(替代 SharedPreferences 时的注意点)

1. 使用 Handler 或 WorkManager 替代 Timer(更适配 Android 生命周期):
  • Timer 缺陷:后台可能被系统杀死,且非精准定时。
  • 推荐方案
    • Handler + postDelayed(短时定时,如每分钟检查一次):
      private final Handler handler = new Handler(Looper.getMainLooper());
      private final Runnable checkRunnable = this::checkTokenExpire;// 启动定时任务
      handler.postDelayed(checkRunnable, 60 * 1000);// 停止任务(如 Activity 销毁时)
      handler.removeCallbacks(checkRunnable);
      
    • WorkManager(长时后台定时,适合低功耗场景):
      WorkRequest workRequest = PeriodicWorkRequestBuilder<TokenCheckWorker>(15, TimeUnit.MINUTES).setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()).build();
      WorkManager.getInstance(context).enqueueUniquePeriodicWork("token_check",ExistingWorkPolicy.KEEP,workRequest
      );
      
2. 减少定时任务频率
  • 结合 MMKV 的高性能,无需频繁检查(建议 5-15 分钟一次),主要依赖网络请求时的实时校验(每次请求前调用 getValidToken())。
面试扩展
后台任务优化:省电与可靠性

面试高频考点

  • 如何优化后台任务以避免耗电?
  • 对比 Timer、Handler、WorkManager 的优劣。

解决方案

  • WorkManager:替代 Timer 实现定时 Token 检查。
    PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(TokenCheckWorker.class,15, TimeUnit.MINUTES
    )
    .setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
    .build();
    WorkManager.getInstance(context).enqueue(workRequest);
    
  • 条件约束:仅在 Wi-Fi 连接时执行任务,避免移动数据下频繁请求。

面试官追问

  • Q:WorkManager 在 API 23 以下的设备如何兼容?
    • A
      1. 使用 WorkManager 1.0.0+:内部已处理兼容性问题。
      2. 回退方案:对于 API < 14 的设备,使用 AlarmManager 实现基本定时功能。

六、进阶优化(面试官可能深挖的点)

1. 数据加密增强
  • MMKV 支持自定义加密(如 AES),对 Token 这种敏感数据,初始化时设置加密密钥:
    // 使用 AES 加密(需处理密钥存储,建议结合 Keystore)
    MMKV mmkv = MMKV.mmkvWithID("encrypted_mmkv", MMKV.MULTI_PROCESS, new AESKeyProvider("你的密钥"));
    
2. 内存泄漏预防
  • MMKV 本身基于文件映射,不会导致内存泄漏,但定时器(如 Handler)需在页面销毁时移除回调,避免持有 Activity 引用。
3. 多版本兼容性
  • MMKV 支持 Android 4.0+(API 14),需注意在旧版本设备上的 mmap 限制(如文件大小上限),但 Token 存储量小,几乎无影响。

面试总结

1. 如何设计安全的 Token 存储方案?

标准答案

  1. 加密存储:使用EncryptedSharedPreferences或 MMKV 的 AES 加密,防止明文泄露。
  2. 双 Token 机制accessToken(短有效期)+ refreshToken(长有效期),减少登录频率。
  3. 时间戳校验:每次请求携带时间戳,服务端验证时间差(如 5 分钟内有效)。
  4. 签名机制:将 Token、时间戳、请求参数组合后用 HMAC-SHA256 签名,防止参数篡改。
2. 如何处理 Token 过期?

标准答案

  1. 自动续期:通过refreshToken获取新的accessToken,减少用户感知。
  2. 网络拦截器:统一处理 401 错误,自动重试或跳转登录。
  3. 手动处理:清除本地 Token 并跳转登录页,同时通过 EventBus 通知 UI 层。
3. 如何实现多端密码修改同步?

标准答案

  1. WebSocket 长连接:接收服务端密码修改通知,立即清除本地 Token。
  2. 版本号校验:每次请求携带token_version,服务端检测版本号是否一致。
  3. 定时任务:使用 WorkManager 定时检查 Token 有效性,确保最终一致性。
4. 如何优化后台任务以避免耗电?

标准答案

  1. 使用 WorkManager:替代 Timer,利用系统调度优化资源。
  2. 条件约束:仅在 Wi-Fi 连接时执行任务,避免移动数据下频繁请求。
  3. 精确唤醒:通过setExact()setAndAllowWhileIdle()控制唤醒时间。

总结:技术方案的核心优势

技术点解决的问题面试加分项
加密存储Token 明文泄露风险提到EncryptedSharedPreferences和 MMKV 的加密实现
双 Token 机制频繁登录问题说明accessTokenrefreshToken的协作流程
WebSocket 通知多端数据一致性问题结合服务端主动通知和本地校验逻辑
WorkManager后台任务耗电问题对比 Timer、Handler,强调系统调度优势
时间戳 + 签名中间人攻击和参数篡改风险展示具体实现代码(如 HMAC-SHA256)

       通过以上方案,既能满足多端密码验证同步的核心需求,又能覆盖安全存储网络优化后台任务知识点

相关文章:

  • 分布自定义shell脚本(详写)附带全代码
  • 【OC】AVPlayerLayer的学习
  • 深入解析主流数据库体系架构:从关系型到云原生
  • 从malloc到free:动态内存管理全解析
  • 【某比特币网址请求头部sign签名】RSA加密逆向分析
  • 在 Linux 上部署 .NET Core 应用并配置为开机自动启动
  • select、poll、epoll实现多路复用IO并对比差异
  • 家庭电脑隐身后台自动截屏软件,可远程查看
  • 十倍开发效率 - IDEA插件之 Maven Helper
  • QT常见输入类控件及其属性
  • SpringCloud小白入门+项目搭建
  • 秒杀抢购系统架构与优化全解:从业务特性到技术落地
  • 软考高级系统架构设计师-第13章 软件可靠性基础知识
  • 32-工艺品商城小程序
  • Redis 事件循环(Event Loop)
  • 无法右键下载文档?网页PDF下载方法大全
  • Opencv图像处理:模板匹配对象
  • 基于docker-java封装的工具类
  • Spring Boot 集成Poi-tl实现动态Word文档生成
  • Linux学习——TCP
  • 内部敏感文件遭万人共享,特朗普政府又曝安全漏洞
  • 淄博张店区国资公司挂牌转让所持“假国企”股权,转让底价为1元
  • 亲诚惠容行大道,命运与共开新篇——中共中央政治局委员、外交部长王毅谈习近平主席对越南、马来西亚、柬埔寨进行国事访问
  • 强对流+暴雨+大雾,中央气象台三预警齐发
  • 黄仁勋:英伟达坚定不移服务中国市场,AI将在每个行业引发颠覆性变革
  • 女子斥“老法师”涉嫌偷拍?街头摄影的边界应该怎么定?