V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Aluhao
V2EX  ›  问与答

React Native 用 axios 上传文件 PHP 后端接收不到,是二者之间传输协议问题吗?

  •  
  •   Aluhao · 2018-04-23 09:20:04 +08:00 · 4506 次点击
    这是一个创建于 2193 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这坑好几天了没填满呀,我用 html 加载 axios 都可以上传,在 RN 里就不行了,有没有遇到类似问题的? HTML 写法

    var data = new FormData();

    data.append('avatar', $('#file')[0].files[0]);

    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

    axios.post('http://127.0.0.1//api/post/', data)

    .then(function (response) {

    console.log(response);
    

    }) .catch(function (error) {

    console.log(error);
    

    });

    });

    在 RN 里也是用 FormData 为么就不行?

    17 条回复    2018-04-24 09:55:47 +08:00
    swirling
        1
    swirling  
       2018-04-23 09:25:15 +08:00
    form data 是浏览器的 API. 你 RN 哪里有浏览器?
    Aluhao
        2
    Aluhao  
    OP
       2018-04-23 09:26:11 +08:00
    @swirling 请教一下,RN 有什么方式呀?
    Aluhao
        3
    Aluhao  
    OP
       2018-04-23 09:28:12 +08:00
    @swirling FormData 这个是构造虚拟表单,RN 应该支持吧。
    SourceMan
        4
    SourceMan  
       2018-04-23 09:30:26 +08:00   ❤️ 1
    帮你使用 Google 搜索了关键字 ·fetch file upload react native·
    https://github.com/g6ling/React-Native-Tips/tree/master/How_to_upload_photo%2Cfile_in%20react-native
    这篇文章里有提到 new FormData();
    Pastsong
        5
    Pastsong  
       2018-04-23 09:34:59 +08:00 via Android
    form data 的 content type 不是 urlencode...
    Aluhao
        6
    Aluhao  
    OP
       2018-04-23 09:39:27 +08:00
    @Pastsong 用 application/octet-stream 和 multipart/form-data 都试过了都不行,PHP 后台接收不到
    chairuosen
        7
    chairuosen  
       2018-04-23 09:41:44 +08:00
    RN 能用 jQuery ?
    my101du
        8
    my101du  
       2018-04-23 09:46:38 +08:00
    在 html 里能上传,是指 post 数据到 http://127.0.0.1 正常,对吗?
    到 RN 里后端 php 接收不到数据,是不是因为 RN 编译成 app 后,http://127.0.0.1 是指向“这台手机 /模拟器”?
    wasabia
        9
    wasabia  
       2018-04-23 09:47:57 +08:00   ❤️ 1
    var xhr = new XMLHttpRequest();
    var url = "xxxx";
    xhr.open('POS', url);
    var formdata = new FormData();

    _.map(images, (image, index) => {
    formdata.append('photos[]', {type: "image/jpeg", name: 'image.jpg', uri: image.path});
    })

    xhr.onload = () => {

    }
    xhr.send(formdata);
    Manweill
        10
    Manweill  
       2018-04-23 10:01:20 +08:00   ❤️ 1
    ['Content-Type']='multipart/form-data' 后台是可以收到的

    var formdata = new FormData();
    formdata.append('file', {type: "image/jpeg", name: 'image.jpg', uri: image.path});
    axios({url,formdata})
    Manweill
        11
    Manweill  
       2018-04-23 10:02:21 +08:00
    参数写错了,应该是这样

    var data = new FormData();
    formdata.append('file', {type: "image/jpeg", name: 'image.jpg', uri: image.path});
    axios({url,data})
    Aluhao
        12
    Aluhao  
    OP
       2018-04-23 10:02:54 +08:00
    @Manweill
    @wasabia
    谢谢!
    Aluhao
        13
    Aluhao  
    OP
       2018-04-23 10:03:56 +08:00
    @chairuosen 那个是网页测试的
    luwu1991
        14
    luwu1991  
       2018-04-23 10:53:27 +08:00 via iPhone
    抓包,看看 2 种情况下的上传请求有啥不同
    wentaoliang
        15
    wentaoliang  
       2018-04-23 12:48:29 +08:00
    为啥我印象中 axios 是 post 的是 json 的格式 php 要用 file://input 接收
    dilu
        16
    dilu  
       2018-04-23 21:46:31 +08:00   ❤️ 1
    我用的是 react-native-fetch-blob
    RN 中是这样写的
    ```
    handleSelectPhoto = () => {
    SYImagePicker.asyncShowImagePicker(options)
    .then(photos => {

    if(photos[0])//如果选择了图片
    {
    console.log('upload start');
    RNFetchBlob.fetch("POST",config.baseUrl + config.avatarUpload,{
    'Content-Type' : 'multipart/form-data',
    'token':user.password,
    'phone':user.teacher_phone,
    'isparent':0,
    },[
    {
    name:'file',
    filename:photos[0]['uri'],
    type:'image/jpg',
    data: RNFetchBlob.wrap(photos[0]['uri'])
    }
    ])
    .then((response) => response.json())
    .then((response) => {
    if(1 != response.code)
    {
    Toast.fail(response.msg);
    return false;
    }
    Toast.info(response.msg);
    this.setState({
    userAvatar:{uri:config.local + '/public' + response.data.url}
    });

    })
    .catch((err) => {
    console.log(err);
    Toast.fail('网络异常');
    })

    console.log(user);
    }
    })
    .catch(err => {

    })
    }
    ```

    后端是这样写的

    ```
    public function upload()
    {

    $file = $this->request->file('file');
    if (empty($file))
    {
    $this->error(__('No file upload or server upload limit exceeded'));
    }

    //判断是否已经存在附件
    $sha1 = $file->hash();

    $upload = Config::get('upload');

    preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
    $type = strtolower($matches[2]);
    $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
    $size = (int) $upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
    $fileInfo = $file->getInfo();
    $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
    $suffix = $suffix ? $suffix : 'file';

    $mimetypeArr = explode(',', $upload['mimetype']);
    $typeArr = explode('/', $fileInfo['type']);
    //验证文件后缀
    if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr) && !in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))
    {
    $this->error(__('Uploaded file format is limited'));
    }
    $replaceArr = [
    '{year}' => date("Y"),
    '{mon}' => date("m"),
    '{day}' => date("d"),
    '{hour}' => date("H"),
    '{min}' => date("i"),
    '{sec}' => date("s"),
    '{random}' => Random::alnum(16),
    '{random32}' => Random::alnum(32),
    '{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'],
    '{suffix}' => $suffix,
    '{.suffix}' => $suffix ? '.' . $suffix : '',
    '{filemd5}' => md5_file($fileInfo['tmp_name']),
    ];
    $savekey = $upload['savekey'];
    $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);

    $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
    $fileName = substr($savekey, strripos($savekey, '/') + 1);
    //
    $splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
    if ($splInfo)
    {
    $imagewidth = $imageheight = 0;
    if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']))
    {
    $imgInfo = getimagesize($splInfo->getPathname());
    $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
    $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
    }
    $params = array(
    'filesize' => $fileInfo['size'],
    'imagewidth' => $imagewidth,
    'imageheight' => $imageheight,
    'imagetype' => $suffix,
    'imageframes' => 0,
    'mimetype' => $fileInfo['type'],
    'url' => $uploadDir . $splInfo->getSaveName(),
    'uploadtime' => time(),
    'storage' => 'local',
    'sha1' => $sha1,
    );
    $attachment = model("attachment");
    $attachment->data(array_filter($params));
    $attachment->save();
    \think\Hook::listen("upload_after", $attachment);
    //进行身份判断 将头像 url 写入到数据库中
    if(isset($this->user['teacher_phone']))
    {
    db('teacher')->where('teacher_phone',$this->user['teacher_phone'])
    ->setField('avatar',$uploadDir . $splInfo->getSaveName());
    }
    else if (isset($this->user['parent_phone']))
    {

    db('parents')->where('parent_phone',$this->user['parent_phone'])
    ->setField('avatar',$uploadDir . $splInfo->getSaveName());
    }

    $this->success(__('Upload successful'), $attachment);
    }
    else
    {
    // 上传失败获取错误信息
    $this->error($file->getError());
    }
    }
    ```
    希望能帮到你
    Aluhao
        17
    Aluhao  
    OP
       2018-04-24 09:55:47 +08:00
    @dilu 谢谢!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5344 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 01:28 · PVG 09:28 · LAX 18:28 · JFK 21:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.