简体   繁体   中英

How to send and receive web service requests and responses in iOS?

I have a Apache CXF-based web service and Android application, which sends requests to it using the code below.

Now I want to write a simple iOS app, which sends same requests to the same web service, but from an iOS device.

What is a good starting point for learning how to use

  1. JSON,
  2. sending web service requests and
  3. receiving responses from the server

in Objective C?

SaveLocationAsyncTask.java

public class SaveLocationAsyncTask extends
        AbstractAsyncTask<SaveLocationRequest, SaveLocationResponse> implements
        ISaveLocationAsyncTask {
    private static final String SERVICE_NAME = "SaveLocation";

    public SaveLocationAsyncTask(final IWebServiceTaskHelper aHelper,
            final ILogger aLogger, final IServerUrlStorage aServerUrlStorage) {
        super(aHelper, SaveLocationResponse.class, aLogger,
                new CbResponseParser<SaveLocationResponse>(), aServerUrlStorage,
                SERVICE_NAME);
    }
}

AbstractAsyncTask.java

import android.os.AsyncTask;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.concurrent.ExecutionException;

public class AbstractAsyncTask<Request, Response> extends
        AsyncTask<String, String, Response> implements
        IRequestSender<Request, Response> {

    private static final String REQUEST_AS_JSON_PARAMETER_NAME = "request";
    private IWebServiceTaskHelper helper;
    private Class<Response> responseClass;
    private ILogger logger = null;
    private IResponseParser<Response> responseParser = null;
    private IServerUrlStorage serverUrlStorage;
    private String serviceName;

    public AbstractAsyncTask(final IWebServiceTaskHelper aHelper,
                             final Class<Response> aResponseClass, final ILogger aLogger,
                             final IResponseParser<Response> aResponseParser,
                             final IServerUrlStorage aServerUrlStorage, final String aServiceName) {
        helper = aHelper;
        responseClass = aResponseClass;
        logger = aLogger;
        responseParser = aResponseParser;
        serverUrlStorage = aServerUrlStorage;
        serviceName = aServiceName;
    }

    private String convertToJson(final Object aRequest) {
        final ObjectMapper mapper = new ObjectMapper();
        String json = null;

        try {
            json = mapper.writeValueAsString(aRequest);
        } catch (final JsonProcessingException exception) {
            logger.error(exception);
        }
        return json;
    }

    @Override
    protected Response doInBackground(final String... aParams) {
        logger.debug("doInBackground: " + aParams);
        return new ResponseProcessor<Response>(logger, helper, responseParser,
                responseClass).processResponse(aParams);
    }

    @Override
    public Response sendRequest(final Request aRequest)
            throws InterruptedException, ExecutionException {
        final String json = convertToJson(aRequest);
        final String url = serverUrlStorage.getServerUrl() + serviceName;

        helper.addNameValuePair(REQUEST_AS_JSON_PARAMETER_NAME, json);

        execute(url);

        return get();
    }
}

CbResponseParser.java:

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public class CbResponseParser<Response> implements IResponseParser<Response> {

    @Override
    public Response parseResponse(final String aResponseAsString,
                                  final Class<Response> aClass) throws IOException, JsonParseException,
            JsonMappingException {
        final ObjectMapper mapper = new ObjectMapper();
        final Response response = mapper.readValue(aResponseAsString, aClass);

        return response;
    }
}

Update 1 (14.06.2014 15:47 MSD):

I've tried DJ_Lectr0's approach. There is one problem: The server can't find the web service. Here's the log output:

WARNING: No operation matching request path "/mobilecsdemo-server/mobilecsdemo/TestMessage" is found, Relative Path: /, HTTP Method: POST, ContentType: application/json, Accept: application/json,. Please enable FINE/TRACE log level for more details.

Fragment of beans.xml :

<bean id="TestMessage" class="ru.mycompany.mobilecsdemo.server.services.TestMessage"/>

<jaxrs:server id="services" address="/">
    <jaxrs:serviceBeans>
        <ref bean="TestMessage"/>
    </jaxrs:serviceBeans>
</jaxrs:server>

TestMessage bean:

@Path("/TestMessage")
public class TestMessage {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestMessage.class);

    @POST
    @Produces("text/plain")
    public String processTestMessage(@FormParam("request") final String aRequest)
    {
        try {
            final ObjectMapper mapper = new ObjectMapper();
            final TestMessageRequest request = mapper.readValue(aRequest,
                    TestMessageRequest.class);

            final TestMessageResponse response = new TestMessageResponse();

            response.setResponse(request.getMessage() + " - Response");

            return mapper.writeValueAsString(response);
        } catch (final JsonParseException exception) {
            LOGGER.error("getUserId", exception);
        } catch (final JsonMappingException exception) {
            LOGGER.error("getUserId", exception);
        } catch (final IOException exception) {
            LOGGER.error("getUserId", exception);
        }

        return "";
    }
}

The URL of the web service TestMessage seems to be http://AAA.BBB.CCC.DDD:8080/mobilecsdemo-server/mobilecsdemo/TestMessage .

Code for sending the request at the iOS side:

NSDictionary *data = [NSDictionary dictionaryWithObject:@"test sending ios" forKey:@"message"];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:kNilOptions error:&error];

NSURL *url = [NSURL URLWithString:@"http://AAA.BBB.CCC.DDD:8080/mobilecsdemo-server/mobilecsdemo/TestMessage"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url cachePolicy:nil timeoutInterval:60];
[req setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[req setValue:[NSString stringWithFormat:@"%d", [jsonData length]] forHTTPHeaderField:@"Content-Length"];
[req setHTTPMethod:@"POST"];
[req setHTTPBody:jsonData];
NSString *retStr = [[NSString alloc] initWithData:[NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil] encoding:NSUTF8StringEncoding];

NSLog(@"Response: %@", retStr);

http://AAA.BBB.CCC.DDD:8080/mobilecsdemo-server/mobilecsdemo?_wadl shows following:

<application xmlns="http://wadl.dev.java.net/2009/02" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <grammars/>
    <resources base="http://AAA.BBB.CCC.DDD:8080/mobilecsdemo-server/mobilecsdemo/">
        <resource path="/TestMessage">
            <method name="POST">
                <request>
                    <representation mediaType="application/x-www-form-urlencoded">
                        <param name="request" style="query" type="xs:string"/>
                    </representation>
                </request>
                <response>
                    <representation mediaType="text/plain">
                        <param name="result" style="plain" type="xs:string"/>
                    </representation>
                </response>
            </method>
        </resource>
    </resources>
</application>

I tried to change Accept and Content-Type to application/x-www-form-urlencoded on the iOS side, but it didn't help.

Update 2 (16:36 MSD): Tried to send a request with Fiddler2 and this one works:

提琴手的要求

Update 3 (17:12 MSD): This one seems to work.

NSDictionary *data = [NSDictionary dictionaryWithObject:@"test sending ios" forKey:@"message"];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:kNilOptions error:&error];

NSURL *url = [NSURL URLWithString:@"http://AAA.BBB.CCC.DDD:8080/mobilecsdemo-server/mobilecsdemo/TestMessage"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url cachePolicy:nil timeoutInterval:60];


[req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[req setValue:[NSString stringWithFormat:@"%d", [jsonData length]] forHTTPHeaderField:@"Content-Length"];
[req setHTTPMethod:@"POST"];

NSString* body = @"request={\"message\":\"message content\"}";
NSData *someData = [body dataUsingEncoding:NSUTF8StringEncoding];

[req setHTTPBody:someData];
NSString *retStr = [[NSString alloc] initWithData:[NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil] encoding:NSUTF8StringEncoding];

NSLog(@"jsonData: %@", jsonData);
NSLog(@"Response: %@", retStr);

This will serve you. Adjust the NSDictionary to your needs.

NSDictionary *data = [NSDictionary dictionaryWithObject:@"test sending ios" forKey:@"value1"];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:kNilOptions error:&error];

    NSURL *url = [NSURL URLWithString:@"http://webserveraddress"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url cachePolicy:nil timeoutInterval:60];
[req setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[req setValue:[NSString stringWithFormat:@"%d", [jsonData length]] forHTTPHeaderField:@"Content-Length"];
[req setHTTPMethod:@"POST"];
[req setHTTPBody:jsonData];
NSString *retStr = [[NSString alloc] initWithData:[NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil] encoding:NSUTF8StringEncoding];

Also there is a asynchronous method for NSURLConnection:

    [NSURLConnection sendAsynchronousRequest:req queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *res3, NSData *data, NSError *connectionError) {
NSString *retStr = [[NSString alloc] initWithData:data];
}

And as mentioned in the comments by Rohan Panchal AFNetworking is a really great 3rd-Party library wrapping these methods nicely. I personally prefer the bare bone NSURLConnection methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM