Как загрузить фотографию на бэкэнд-сервер вместе с данными формы с помощью API? - PullRequest
1 голос
/ 15 марта 2019

Здесь ниже мой код, я пытаюсь захватить изображение и заполнить другое поле ввода. Как только я нажимаю кнопку «Создать», я вызываю API для загрузки его на внутренний сервер. Но как мне отправить данные файла в бэкэнд? У меня есть рабочий API в почтальоне. И некоторые из полей, которые я здесь не включил, представляют собой некоторый код входного поля, потому что код здесь будет большим.

API принимает следующие поля в почтальоне

enter image description here

   import React, {Component} from 'react';
    import {
        StyleSheet,
        Button,
        TextInput,
        Text,
        TouchableOpacity,
        View,
        Picker,
        Image,
    } from 'react-native';
    import ImagePicker from 'react-native-image-picker';

    export default class CreateStudent extends React.Component {
        constructor(props){
            super(props);
            this.state = {
                studentName: '',
                email: '',
                newPassword: '',
                fileShow: '',
                faceDetails: '',
                school: 1,
            }
        }

        handleEmail = (text) => {
            this.setState({ email: text })
        }

        handlePassword = (text) => {
            this.setState({ newPassword: text })
        }

        handleName = (text) => {
            this.setState({ studentName: text })
        }

        selectImage = () => {
            const options = {
                quality: 1.0,
                maxWidth: 75,
                maxHeight: 75
            }
            ImagePicker.launchCamera(options,(responce)=>{
                const fileDetails ={
                    uri : responce.uri,
                    name :responce.fileName,
                    method: 'POST',
                    width : 50,
                    height : 50,
                    path : responce.path,
                    type :  responce.type,
                  }
                 this.setState({
                    fileShow: responce.uri,
                    faceDetails: fileDetails
                 })
                console.log(this.state.fileShow);
                console.log(fileDetails);
            })
        }

        async onCreateStudentPressed() {
            try {
                let response = await fetch('http://10.0.2.2:5000/api/students/create', {
                    method: 'POST',
                    headers: {
                       'Accept': 'application/json',
                       'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                         file: this.state.fileDetails,
                         email: this.state.email,
                         password: this.state.newPassword,
                         phone_number: this.state.phoneNumber,
                         class: this.state.class,
                         section: this.state.section,
                         school: this.state.school,
                         name: this.state.studentName
                    })
                });
                let res = await response.text();
                if (response.status >= 200 && response.status < 300) {
                     //Handle success
                     let accessToken = res;
                     console.log(accessToken);
                     //On success we will store the access_token in the AsyncStorage
                     //this.storeToken(accessToken);
                } else {
                     //Handle error
                     let error = res;
                     throw error;
                }
            } catch(error) {
                this.setState({error: error});
                console.log("error " + error);
                this.setState({
                   passwordUpdated: false
                })
            }
         }

        render() {
            return (
                <View>
                    <View style={styles.formContainer}>
                        <Text style ={styles.pageTitle} >Create Student</Text>
                        <View style={styles.Camera}>
                            <TouchableOpacity onPress={this.selectImage}>
                              <Text>Take Picture</Text>
                            </TouchableOpacity>
                        </View>
                        {
                            this.state.fileShow !== '' ?
                            <View style={styles.showBlack}>
                                <View style={styles.placeholder}>
                                    <Image key={1} source={{uri: this.state.fileShow}} style={styles.previewImage} />
                                </View>
                            </View>
                            :
                            null
                        }
                        <TextInput
                            placeholder='Enter Student Name'
                            placeholderTextColor='#808080'
                            style ={styles.textInput}
                            underlineColorAndroid={'transparent'}
                            onChangeText = {this.handleName}
                        />
                        <TextInput
                            placeholder='Enter Student Email'
                            placeholderTextColor='#808080'
                            style ={styles.textInput}
                            underlineColorAndroid={'transparent'}
                            onChangeText = {this.handleEmail}
                        />
                        <TextInput
                            placeholder='Enter Password'
                            placeholderTextColor='#808080'
                            secureTextEntry={true}
                            style ={styles.textInput}
                            underlineColorAndroid={'transparent'}
                            onChangeText = {this.handlePassword}
                        />
                        <Button
                            onPress={this.onCreateStudentPressed.bind(this)}
                            style ={styles.loginBtn}
                            title="Create"
                        />
                    </View>  
                </View>
            );
        }
    }

1 Ответ

0 голосов
/ 15 марта 2019

Существуют различные способы достижения этого.Я собираюсь выделить самый простой способ для вас сделать это.Я предполагаю, что у вас есть сервис хранения, такой как Amazon S3, где вы храните фотографию.Самый простой способ - сначала загрузить изображение на свой S3, в теле ответа будет указан URL-адрес загруженной фотографии.Затем вы можете взять этот URL вместе со своими значениями формы и передать их в бэкэнд.

//Example.js

    import React, { Component } from 'react';
    import {
        //Whatever RN Components you need
        StyleSheet,
        Text,
        View,
        Alert,
        TouchableHighlight,
        TextInput,
        ActivityIndicator,
        ScrollView,
        Picker,
        Linking,
        Image,
    } from 'react-native';
    import axios from 'axios';
    import { RNS3 } from 'react-native-aws3';
    import ImagePicker from 'react-native-image-picker';

    export default class RegisterScreen extends Component {
    state = {
            email: '',
            password: '',
            confirmedPassword: '',
            firstName: '',
            lastName: '',
            avatar: '',
            avatarUri: '',
            avatarName: '',
            avatarType: '',
            loading: false,
            errorMessage: '',
            uploadMessage: ''
        }

        onRegisterPress = () => {
            this.setState({ 
                errorMessage: '',
                registerLoading: true,
                uploadMessage: 'This may take a while: Uploading your Profile Pic...'
            });
            const avatarFile = {
                uri: this.state.avatarUri,
                name: this.state.avatarName,
                type: this.state.avatarType
            };
            const avatarOptions = {
                keyPrefix: 'uploads/path/avatar/' + this.state.email + '/' + new Date().getTime(),
                bucket: 'your-bucket-s3',
                region: 'us-west-2',
                accessKey: 'ACCESSKEY',
                secretKey: 'SECRETKEY',
                successActionStatus: 201
            };
            RNS3.put(avatarFile, avatarOptions)
            .then((response) => {
                if (response.status === 201) {
                    this.setState({ avatar: response.body.postResponse.location });
                } else {//handle error}
            })
            .then(() => {
                    this.setState({
                        uploadMessage: 'Creating your profile'
                    });
                    const url = 'someremoteurl.com';
                    const payload = {
                        email: this.state.email,
                        password: this.state.password,
                        password_confirmation: this.state.confirmedPassword,
                        first_name: this.state.firstName,
                        last_name: this.state.lastName,
                        avatar: this.state.avatar,
                    };
                    axios.post(url, payload)
                    .then((r) => {
                        this.setState({
                            uploadMessage: '',
                            loading: false
                        });
                        if (r.status === 200) {
                            //handle success
                        }
                    })
                    .catch(() => {
                        // handle form submission error
                        this.setState({
                            uploadMessage: '',
                            loading: false,
                            error: true
                        });
                    });
                });
            }



        openMediaLibrary() {
            const options = {
                title: 'Select Photo',
                storageOptions: {
                    skipBackup: true,
                    path: 'images'
                }
            };
            ImagePicker.showImagePicker(options, (response) => {
                console.log('Response = ', response);

                if (response.didCancel) {
                    console.log('Cancelled selection of image');
                } else if (response.error) {
                    console.log('Image Picker error', response.error)
                } else {
                    this.setState({
                        avatarUri: response.uri,
                        avatarName: response.fileName,
                        avatarType: response.type
                    });
                }
            });
        }

        render() {
            return (
                <ScrollView style={{ margin: 15 }}>
                    <View style={styles.formField}>
                        <Text style={styles.formLabelStyle}> Email</Text>
                        <TextInput
                            placeholder='john@yahoo.com'
                            underlineColorAndroid='transparent'
                            onChangeText={(email) => this.setState({ email })}
                            value={this.state.email}
                            autoCapitalize='none'
                        />
                    </View>

                    <View style={styles.formField}> 
                        <Text style={styles.formLabelStyle}> Password (minimum of 8 letters)</Text>
                        <TextInput
                            placeholder='password'
                            underlineColorAndroid='transparent'
                            onChangeText={(password) => this.setState({ password })}
                            value={this.state.password}
                            secureTextEntry
                            autoCorrect={false}
                            autoCapitalize='none'
                        />
                    </View>

                    <View style={styles.formField}> 
                        <Text style={styles.formLabelStyle}> Password Confirmation</Text>
                        <TextInput
                            placeholder='retype your password'
                            underlineColorAndroid='transparent'
                            onChangeText={(confirmedPassword) => this.setState({ confirmedPassword })}
                            value={this.state.confirmedPassword}
                            secureTextEntry
                            autoCorrect={false}
                            autoCapitalize='none'
                        />
                    </View>

                    <View style={styles.formField}> 
                        <Text style={styles.formLabelStyle}> First Name</Text>
                        <TextInput
                            placeholder='First Name'
                            underlineColorAndroid='transparent'
                            onChangeText={(firstName) => this.setState({ firstName })}
                            value={this.state.firstName}
                        />
                    </View>

                    <View style={styles.formField}> 
                        <Text style={styles.formLabelStyle}>Last Name</Text>
                        <TextInput
                            placeholder='Last Name'
                            underlineColorAndroid='transparent'
                            onChangeText={(lastName) => this.setState({ lastName })}
                            value={this.state.lastName}
                        />
                    </View>
                    <View>
                        <View style={{ padding: 10 }}>
                        {
                            this.state.avatarUri.length > 0 ?
                            <Image 
                                source={{ uri: this.state.avatarUri }}
                                style={{ width: 140, height: 140 }}
                            />
                            : null
                        }
                        </View>
                        <Button 
                            small
                            backgroundColor='#13CE66'
                            title={(this.state.avatarUri.length === 0) ? 
                                'Choose Profile Picture' : 'Change Profile Picture'}
                            onPress={() => this.openMediaLibrary()}
                        />
                    </View>
                    <Button 
                            large
                            backgroundColor='#13CE66'
                            title='Submit'
                            onPress={() => this.onRegisterPress() }
                        />
                </ScrollView>
            )
        }
}

Поэтому, когда вы пытаетесь зарегистрировать этого пользователя, изображение сначала загружается, а полученный URL сохраняется в состоянии, чтобыиспользоваться как часть параметров формы для аватара.Это легко, недостатком является необходимость ждать ответа загрузки перед тем, как отправлять параметры формы

РЕДАКТИРОВАТЬ

Если вы не используете стороннюю службу хранения или предпочитаете отправлятьфайл на ваши собственные серверы, затем используйте FormData():

//OnRegisterPress function should look like this:
onRegisterPress = () => {
    let form = new FormData();
    form.append('avatar', {
        //from openMedia Function, image selected with image-picker
        uri: this.state.avatarUri,
        name: this.state.avatarName,
        type: this.state.avatarType  
    });
    // append your other params such as email, password, name

    form.append('email', this.state.email)
    form.append('password', this.state.password)

    // when you are done appending, use fetch to send the form data as axios seems to be having a bit of issues doing this.

   fetch('http://yourapiendpoint', {  
       headers: {
           'Accept': 'application/json',
           'Content-Type': 'multipart/form-data'
       },
       method: 'POST',
       body: form
   });
}
...