fix(cors): 修复H5环境下的CORS上传问题
- 在config/dev.ts中添加代理配置,将/api/*请求代理到外部API服务器 - 在bowongAISDK.ts中添加平台检测逻辑,H5环境使用fetch避免CORS - 新增H5专用的文件上传和图像生成方法 - 保持小程序环境使用原有的Taro.uploadFile方法 - 确保跨平台兼容性,解决XMLHttpRequest凭据模式与通配符CORS头冲突 修复错误: - Access-Control-Allow-Origin头在凭据模式下不能使用通配符* - H5环境下uploadFile自动设置withCredentials导致的CORS阻止
This commit is contained in:
parent
6c4247c8ea
commit
595e56378c
|
|
@ -7,6 +7,24 @@ export default {
|
|||
devServer: {
|
||||
fs: {
|
||||
allow: ['..']
|
||||
},
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'https://bowongai-test--text-video-agent-fastapi-app.modal.run',
|
||||
changeOrigin: true,
|
||||
secure: true,
|
||||
configure: (proxy, _options) => {
|
||||
proxy.on('error', (err, _req, _res) => {
|
||||
console.log('proxy error', err);
|
||||
});
|
||||
proxy.on('proxyReq', (proxyReq, req, _res) => {
|
||||
console.log('Sending Request to the Target:', req.method, req.url);
|
||||
});
|
||||
proxy.on('proxyRes', (proxyRes, req, _res) => {
|
||||
console.log('Received Response from the Target:', proxyRes.statusCode, req.url);
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,152 @@ export class BowongAISDK {
|
|||
/** API 服务基础地址 */
|
||||
private readonly baseUrl = 'https://bowongai-test--text-video-agent-fastapi-app.modal.run';
|
||||
|
||||
/**
|
||||
* 检查当前是否为H5平台
|
||||
* @private
|
||||
*/
|
||||
private _isH5Platform(): boolean {
|
||||
return process.env.TARO_ENV === 'h5';
|
||||
}
|
||||
|
||||
/**
|
||||
* H5平台专用的文件上传方法
|
||||
* 使用Taro.request避免CORS问题
|
||||
* @private
|
||||
*/
|
||||
private async _uploadFileForH5(params: UploadParams): Promise<string> {
|
||||
const { filePath, name, type, onProgress } = params;
|
||||
const url = `${this._isH5Platform() ? '' : this.baseUrl}/api/file/upload/s3`;
|
||||
|
||||
try {
|
||||
// 获取文件信息
|
||||
let fileInfo;
|
||||
try {
|
||||
fileInfo = await Taro.getFileInfo({ filePath });
|
||||
if (!isGetFileInfoSuccessCallbackResult(fileInfo)) {
|
||||
console.warn('获取文件信息失败,使用默认值');
|
||||
fileInfo = { size: 0 };
|
||||
}
|
||||
} catch (getFileInfoError) {
|
||||
console.warn('getFileInfo调用失败,使用默认值:', getFileInfoError);
|
||||
fileInfo = { size: 0 };
|
||||
}
|
||||
|
||||
// 自动生成文件名(如果未提供)
|
||||
const fileName = name || `upload_${Date.now()}.${this._getFileExtension(filePath)}`;
|
||||
// 自动判断文件类型(如果未提供)
|
||||
const fileType = type || this._getMimeType(filePath);
|
||||
|
||||
console.log('开始上传文件 (H5模式):', {
|
||||
fileName,
|
||||
fileSize: fileInfo.size,
|
||||
fileType
|
||||
});
|
||||
|
||||
// 创建FormData
|
||||
const formData = new FormData();
|
||||
|
||||
// 在H5环境中,需要先将filePath转换为File对象
|
||||
const response = await fetch(filePath);
|
||||
const blob = await response.blob();
|
||||
const file = new File([blob], fileName, { type: fileType });
|
||||
|
||||
formData.append('file', file);
|
||||
formData.append('filename', fileName);
|
||||
formData.append('type', fileType);
|
||||
|
||||
// 使用fetch进行上传
|
||||
const uploadResponse = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!uploadResponse.ok) {
|
||||
throw new Error(`HTTP ${uploadResponse.status}: 文件上传失败`);
|
||||
}
|
||||
|
||||
const result: ApiResponse<string> = await uploadResponse.json();
|
||||
|
||||
if (!result.status) {
|
||||
throw new Error(result.msg || '文件上传失败');
|
||||
}
|
||||
|
||||
console.log('文件上传成功 (H5模式):', result.data);
|
||||
return result.data;
|
||||
|
||||
} catch (error) {
|
||||
console.error('H5文件上传失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* H5平台专用的图像生成方法
|
||||
* @private
|
||||
*/
|
||||
private async _generateImageForH5(params: GenerateImageParams): Promise<string> {
|
||||
const {
|
||||
prompt,
|
||||
model_name = 'gemini-2.5-flash-image-preview',
|
||||
aspect_ratio = '9:16',
|
||||
mode = 'turbo',
|
||||
webhook_flag = false,
|
||||
img_file
|
||||
} = params;
|
||||
|
||||
const url = `${this._isH5Platform() ? '' : this.baseUrl}/api/custom/image/submit/task`;
|
||||
|
||||
try {
|
||||
if (img_file) {
|
||||
// 创建FormData
|
||||
const formData = new FormData();
|
||||
|
||||
// 在H5环境中,需要先将filePath转换为File对象
|
||||
const response = await fetch(img_file);
|
||||
const blob = await response.blob();
|
||||
const fileName = `generate_${Date.now()}.${this._getFileExtension(img_file)}`;
|
||||
const file = new File([blob], fileName, { type: this._getMimeType(img_file) });
|
||||
|
||||
formData.append('img_file', file);
|
||||
formData.append('prompt', prompt);
|
||||
formData.append('model_name', model_name);
|
||||
formData.append('aspect_ratio', aspect_ratio);
|
||||
formData.append('mode', mode.toString());
|
||||
formData.append('webhook_flag', webhook_flag.toString());
|
||||
formData.append('img_url', '');
|
||||
|
||||
// 使用fetch进行上传
|
||||
const uploadResponse = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!uploadResponse.ok) {
|
||||
throw new Error(`HTTP ${uploadResponse.status}: 图像生成请求失败`);
|
||||
}
|
||||
|
||||
const result: ApiResponse<string> = await uploadResponse.json();
|
||||
|
||||
if (!result.status) {
|
||||
throw new Error(result.msg || '图像生成请求失败');
|
||||
}
|
||||
|
||||
console.log('图像生成任务提交成功 (H5模式):', result.data);
|
||||
return result.data;
|
||||
}
|
||||
throw new Error(`请选择图片`)
|
||||
} catch (error) {
|
||||
console.error('H5图像生成失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 上传文件到 S3
|
||||
|
|
@ -70,14 +216,26 @@ export class BowongAISDK {
|
|||
* @returns Promise<string> 返回上传后的文件地址
|
||||
*/
|
||||
async upload(params: UploadParams): Promise<string> {
|
||||
// 如果是H5平台,使用专用的上传方法
|
||||
if (this._isH5Platform()) {
|
||||
return this._uploadFileForH5(params);
|
||||
}
|
||||
|
||||
const { filePath, name, type, onProgress } = params;
|
||||
const url = `${this.baseUrl}/api/file/upload/s3`;
|
||||
|
||||
try {
|
||||
// 获取文件信息
|
||||
const fileInfo = await Taro.getFileInfo({ filePath });
|
||||
if (!isGetFileInfoSuccessCallbackResult(fileInfo)) {
|
||||
throw new Error(fileInfo.errMsg)
|
||||
let fileInfo;
|
||||
try {
|
||||
fileInfo = await Taro.getFileInfo({ filePath });
|
||||
if (!isGetFileInfoSuccessCallbackResult(fileInfo)) {
|
||||
console.warn('获取文件信息失败,使用默认值');
|
||||
fileInfo = { size: 0 };
|
||||
}
|
||||
} catch (getFileInfoError) {
|
||||
console.warn('getFileInfo调用失败,使用默认值:', getFileInfoError);
|
||||
fileInfo = { size: 0 };
|
||||
}
|
||||
// 自动生成文件名(如果未提供)
|
||||
const fileName = name || `upload_${Date.now()}.${this._getFileExtension(filePath)}`;
|
||||
|
|
@ -401,6 +559,11 @@ export class BowongAISDK {
|
|||
* -F 'img_file='
|
||||
*/
|
||||
async generateImage(params: GenerateImageParams): Promise<string> {
|
||||
// 如果是H5平台,使用专用的生成方法
|
||||
if (this._isH5Platform()) {
|
||||
return this._generateImageForH5(params);
|
||||
}
|
||||
|
||||
const {
|
||||
prompt,
|
||||
model_name = 'gemini-2.5-flash-image-preview',
|
||||
|
|
|
|||
Loading…
Reference in New Issue