Skip to content

Commit

Permalink
feat: support dynamic data response
Browse files Browse the repository at this point in the history
  • Loading branch information
ozline committed Dec 28, 2024
1 parent 827ef74 commit ed15caf
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 23 deletions.
78 changes: 64 additions & 14 deletions app/(tabs)/user.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { Buffer } from 'buffer';
import React, { useState } from 'react';
import { Alert, Button, Text } from 'react-native';
import { Alert, Button, Image, Text, View } from 'react-native';

import { ThemedView } from '@/components/ThemedView';
import { get, post } from '@/modules/native-request';

export default function HomePage() {
const [dictionary, setDictionary] = useState<{ [key: string]: string }>({});
const [imageUrl, setImageUrl] = useState<string | null>(null); // 用于显示验证码图片

const url = 'https://jwcjwxt1.fzu.edu.cn/logincheck.asp';
const urlLoginCheck = 'https://jwcjwxt1.fzu.edu.cn/logincheck.asp';
const urlVerifyCode = 'https://jwcjwxt1.fzu.edu.cn/plus/verifycode.asp';
const urlGet = 'https://www.baidu.com';
const headers = {
Referer: 'https://jwch.fzu.edu.cn',
Origin: 'https://jwch.fzu.edu.cn',
Expand All @@ -19,25 +23,52 @@ export default function HomePage() {
passwd: 'student-password',
};

const handlePress = async () => {
const handlePress = async (
url: string,
headers: Record<string, string>,
formData: Record<string, string>,
) => {
try {
const { data: respData, headers: respHeaders } = await post(
url,
headers,
formData,
);
const {
status: respStatus,
data: respData,
headers: respHeaders,
} = await post(url, headers, formData);
setDictionary(respHeaders);
Alert.alert('结果', JSON.stringify(respData));
Alert.alert(
'结果',
respStatus +
'\n' +
JSON.stringify(Buffer.from(respData).toString('utf-8')), // 这里默认了 PSOT 返回的是 JSON 数据
);
} catch (error) {
Alert.alert('错误', String(error));
}
};

const handlePressGet = async () => {
const handlePressGet = async (
url: string,
headers: Record<string, string>,
isBinary = false, // 是否为二进制数据,如果是的话转为 base64输出(只是测试,我们认为二进制数据就是图片)
) => {
try {
const { data: respData, headers: respHeaders } = await get(url, headers);
const {
status: respStatus,
data: respData,
headers: respHeaders,
} = await get(url, headers);
setDictionary(respHeaders);
Alert.alert('结果', JSON.stringify(respData));
// 根据 Content-Type 处理响应数据(可能需要内置一个映射表?)
if (isBinary) {
// 图片
const base64Data = btoa(String.fromCharCode(...respData));
const imageUrl = `data:image/png;base64,${base64Data}`;
setImageUrl(imageUrl); // 保存图片 URL 到状态
} else {
// 其他(默认为文本)
const responseData = Buffer.from(respData).toString('utf-8'); // 使用 Buffer 解码
Alert.alert('结果', respStatus + '\n' + responseData);
}
} catch (error) {
Alert.alert('错误', String(error));
}
Expand All @@ -47,13 +78,32 @@ export default function HomePage() {
<>
<ThemedView>
<Text>User</Text>
<Button title="获取数据POST" onPress={handlePress} />
<Button title="获取数据GET" onPress={handlePressGet} />
<Button
title="获取数据POST"
onPress={() => handlePress(urlLoginCheck, headers, formData)}
/>
<Button
title="获取数据GET"
onPress={() => handlePressGet(urlGet, headers)}
/>
<Button
title="获取验证码图片"
onPress={() => handlePressGet(urlVerifyCode, headers, true)}
/>
{Object.entries(dictionary).map(([key, value]) => (
<Text key={key}>
{key}: {value}
</Text>
))}
{imageUrl && ( // 如果有图片 URL
<View style={{ marginTop: 20, marginLeft: 20 }}>
<Image
source={{ uri: imageUrl }}
style={{ width: 120, height: 35 }}
resizeMode="stretch" // 使用 stretch 来确保图片填满指定的宽高
/>
</View>
)}
</ThemedView>
</>
);
Expand Down
10 changes: 8 additions & 2 deletions modules/native-request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@
// and on native platforms to NativeRequest.ts
import NativeRequestModule from './src/NativeRequestModule';

// 返回格式为 { data: string, headers: Record<string, string> }
// 返回格式为 { status: number, data: Uint8Array, headers: Record<string, string> }
// iOS 原始响应格式为 { status: Int?, data: Data?, headers: Record<string, string>, error: String? }
// Android 原始响应格式为 {待补充}
export async function get(url: string, headers: Record<string, string>) {
const response = await NativeRequestModule.get(url, headers);
if (response.error) {
throw new Error(response.error);
}
return {
status: response.status,
data: response.data,
headers: response.headers,
};
}

// 返回格式为 { data: string, headers: Record<string, string> }
// 返回格式为 { status: number, data: Uint8Array, headers: Record<string, string> }
// iOS 原始响应格式为 { status: Int?, data: Data?, headers: Record<string, string>, error: String? }
// Android 原始响应格式为 {待补充}
export async function post(
url: string,
headers: Record<string, string>,
Expand All @@ -25,6 +30,7 @@ export async function post(
throw new Error(response.error);
}
return {
status: response.status,
data: response.data,
headers: response.headers,
};
Expand Down
18 changes: 11 additions & 7 deletions modules/native-request/ios/NativeRequestModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ struct StringMapper: Record {

// 用于统一返回数据格式
struct ResponseMapper: Record {
// 响应状态码
@Field var status: Int = -1 // 默认为 -1
// 数据内容
@Field var data: String = ""
@Field var data: Data? = nil // 默认为空,需要 SDK50+ 支持
// 响应头
@Field var headers: [AnyHashable: Any] = [:]
// 错误信息
@Field var error: String = ""
@Field var error: String? = nil // 默认不存在错误
}

public class NativeRequestModule: Module {
Expand All @@ -32,7 +34,7 @@ public class NativeRequestModule: Module {
configuration.httpCookieStorage = HTTPCookieStorage.shared
let session = Alamofire.Session(configuration: configuration)

var resp = ResponseMapper(data: "", headers: [:], error: "")
var resp = ResponseMapper(status: -1, data: nil, headers: [:], error: nil)
do {
let response = await session.request(url, headers: HTTPHeaders(headers.data)).serializingData().response
// // 检查请求状态
Expand All @@ -41,7 +43,8 @@ public class NativeRequestModule: Module {
// result["headers"] = response.response?.allHeaderFields ?? [:]
// return result
// }
resp.data = String(data: response.data ?? Data(), encoding: .utf8) ?? "" // 数据内容
resp.status = response.response?.statusCode ?? -1
resp.data = response.data
resp.headers = response.response?.allHeaderFields ?? [:] // Headers
return resp
} catch {
Expand All @@ -55,7 +58,7 @@ public class NativeRequestModule: Module {
let configuration = URLSessionConfiguration.af.default
configuration.httpCookieStorage = HTTPCookieStorage.shared
let session = Alamofire.Session(configuration: configuration)
var resp = ResponseMapper(data: "", headers: [:], error: "")
var resp = ResponseMapper(status: -1, data: nil, headers: [:], error: nil)
do{
let response = await session.request(url, method: .post, parameters: formData.data, encoder: URLEncodedFormParameterEncoder.default, headers: HTTPHeaders(headers.data)).serializingData().response
// // 检查请求状态
Expand All @@ -64,8 +67,9 @@ public class NativeRequestModule: Module {
// result["headers"] = response.response?.allHeaderFields ?? [:]
// return result
// }
resp.data = String(data: response.data ?? Data(), encoding: .utf8) ?? "" // 数据内容
resp.headers = response.response?.allHeaderFields ?? [:] // Headers
resp.status = response.response?.statusCode ?? -1
resp.data = response.data
resp.headers = response.response?.allHeaderFields ?? [:]
return resp
} catch {
resp.error = "请求失败: \(error)"
Expand Down

0 comments on commit ed15caf

Please sign in to comment.