第三章 RN的第一个项目:网络请求的实现

      在我们的项目开发过程中,网络请求是必不可少的。网络请求包含使用客户端代码实现,也可以在js页面直接发起请求。本章重点讲述如何搭建网络架构。

  1. Android端
          架构描述:采用retrofit2实现网络请求。这段代码比较简单,举个简单列子:使用新浪的短链服务生成短链接。我们看下怎么实现。
          网络请求实现,先看retrofit2请求api实现,如下代码:

    public interface RNNetConnectApi {
        //接口请求格式
        @Headers({
                "Content-Type:application/x-www-form-urlencoded",
                "Accept-Charset: utf-8"
        })
    
        //接口名称,这是一个get请求。
        //url_long:我们需要转化的长链接
        @GET("shorten.json")
        Call<String> getShortLinkUrl(@Query("source") String appKey, @Query("url_long") String url_long);
    }
    

    然后我们还要初始化我们的retrofit api句柄.如下代码实现:

       /**
       *retrofit创建
       * @return
       */
       protected void createRetrofit() {
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.connectTimeout((long)this.connectTime, TimeUnit.SECONDS);
            builder.readTimeout((long)this.connectTime, TimeUnit.SECONDS);
            builder.writeTimeout((long)this.connectTime, TimeUnit.SECONDS);
            builder.retryOnConnectionFailure(false);
            builder.addInterceptor(new NetInterceptor());
    
            OkHttpClient okHttpClient = builder.build();
    
            Retrofit retrofit = (new retrofit2.Retrofit.Builder()).baseUrl(urlHost).client(okHttpClient)
                    .addConverterFactory(ScalarsConverterFactory.create()).build();
            rnNetConnectApi = retrofit.create(RNNetConnectApi.class);
        }
    

    定义成功后,我们就可以用这个api接口来创建Call对象,实现网络请求:

    Call call = rnNetConnectApi.getShortLinkUrl(appKey,longUrl);
    call.enqueue(new Callback() {
        @Override
        public void onResponse(Call call, Response response) {
            handleResponse(call,response,callback);
        }
    
        @Override
        public void onFailure(Call call, Throwable t) {
            if ( null != t) {
                Log.d(TAG,"请求失败信息:"+t.getMessage()+" 原因:"+t.getCause());
            }
        }
    });
    

    网络请求成功后,我们在handleResponse这个方法中具体处理。主要的网络处理代码就是这么多。

  2. IOS端
    网络请求架构:我们采用的是AFNetworking架构。代码主要描述如下:
    //执行网络请求

    - (void)getShorLinktUrl: (NSString*)longUrl success:(RCTResponseSenderBlock)callback {
        NSString *urlHost = @"http://api.t.sina.com.cn/short_url/shorten.json?source=3271760578&&url_long=";
      
        urlHost = [urlHost stringByAppendingString:longUrl];
      
        NSURL *url = [NSURL URLWithString: urlHost];
        NSURLSession *session = [NSURLSession sharedSession];
        
        //创建可变的请求对象
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        
        //配置网络请求格式
        NSString *contentType = [NSString stringWithFormat:@"text/plain"];
        [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
        NSString *accept = [NSString stringWithFormat:@"application/json"];
        [request setValue:accept forHTTPHeaderField: @"Accept"];
        
        //建立请求task
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable responseData, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
            if ( nil != httpResponse) {
                NSLog(@"response status = %d",(int)httpResponse.statusCode);
                if ( nil != error) {
                   NSLog(@"response error = %@",error);
                }
            }
            
            //正确的应答
            if ( nil != httpResponse && httpResponse.statusCode == 200) {
                //解析数据:根据需要处理
                //NSString *result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
                NSDictionary *result = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];
                NSLog(@"response result = %@",result);
                
                if ([result isKindOfClass:[NSArray class]]) {
                    NSDictionary *item = (NSDictionary*)[(NSArray*)result objectAtIndex:0];
                    for (NSString *key in item) {
                        //存入数组并同步
                        
                        [[NSUserDefaults standardUserDefaults] setObject:item[key] forKey:key];
                        
                        [[NSUserDefaults standardUserDefaults] synchronize];
                        
                        NSLog(@"key: %@ value: %@", key, item[key]);
                    }
                } else {
                    for (NSString *key in result) {
                        //存入数组并同步
                        
                        [[NSUserDefaults standardUserDefaults] setObject:result[key] forKey:key];
                        
                        [[NSUserDefaults standardUserDefaults] synchronize];
                        
                        NSLog(@"key: %@ value: %@", key, result[key]);
                    }
                }
            }
        }];
        
        //读取数据
        NSString *shortUrl = [[NSUserDefaults standardUserDefaults] objectForKey:@"url_short"];
      
        if ( nil != shortUrl) {
          NSLog(@"shortUrl = %@",shortUrl);
          callback(@[shortUrl,]);
          
        } else {
          callback(@[@"获取失败",]);
        }
      
        [dataTask resume];
    }
    核心代码基本上就这么多。
    
  3. js端
    我们先来看一下使用客户端网络请求,如何操作:

    nativeModule.doNetworkRequest(longUrl,this.callBack);
    

    其中longUrl是我们具体要转成短链的长链接地址,callBack是回调方法,必须加上this调用指定作用域。
    如果需要网页动态刷新显示结果,我们可以用如下方式实现:

        this.setState({
            shortUrl: url,
    
        })
    

    使用setState就会再次调用render方法去刷新,但是使用this.state就不会。注意:必须在构造函数中初始化。类似如下操作;

    constructor(props){
        super(props);
        this.state = {
                   shortUrl: "本地获取数据中。。。",  //这里放你自己定义的state变量及初始值
                   jsUrl: "页面获取数据中。。。",  //这里放你自己定义的state变量及初始值
                };
        this.getDataFromNet();
        this.fetchData();
    }   
    

    否则在render中如果使用state中的变量,就会报null错误。

    看一下第二方式,就是页面直接发起请求,我们使用fetch来实现:

    //由页面发起请求
    fetchData() {
            fetch(urlHost+longUrl)
                .then((response) => response.json())
                .then((responseData) => {
                    //过来的数据是一个JSONArray格式,要使用这种方式取值
                    console.log("responseData[0]=",responseData[0]);
                    //设置3秒后刷新页面
                    setTimeout(()=> {
                        this.setState({
                            jsUrl: responseData[0].url_short,
    
                        });
                    }, delay_time);
                })
                .done();
            //调用了done() —— 这样可以抛出异常而不是简单忽略
        }         
    

    至此,网络请求基本上就实现了。

上一篇:iOS原生混合RN开发最佳实践


下一篇:Linux服务器配置SSH免密登录