564

我很难找到有关如何使用 Android 调用标准 SOAP/WSDL Web 服务的好信息。我所能找到的只是非常复杂的文档和对“kSoap2”的引用,然后是一些关于使用SAX手动解析它们的一些信息。好的,那很好,但现在是 2008 年,所以我认为应该有一些好的库来调用标准 Web 服务。

Web 服务基本上是在NetBeans中创建的。我希望 IDE 支持生成管道类。我只需要最简单/最优雅的方式来从基于 Android 的手机联系基于WSDL的 Web 服务。

4

26 回答 26

251

Android 不提供任何类型的 SOAP 库。您可以自己编写,也可以使用类似kSOAP 2的东西。正如您所注意到的,其他人已经能够在他们自己的项目中编译和使用 kSOAP2,但我不必这样做。

迄今为止,Google 对向 Android 添加 SOAP 库表示兴趣不大。我对此的怀疑是,他们宁愿支持 Web 服务的当前趋势,转向基于 REST 的服务,并使用 JSON 作为数据封装格式。或者,使用 XMPP 进行消息传递。但这只是猜测。

目前,基于 XML 的 Web 服务在 Android 上是一项非常重要的任务。不了解 NetBeans,我无法谈论那里可用的工具,但我同意应该提供更好的库。XmlPullParser 有可能使您免于使用 SAX,但我对此知之甚少。

于 2008-11-19T21:50:32.780 回答
99

org.apache.http.impl.client.DefaultHttpClient默认情况下包含在 Android SDK 中。这将使您连接到 WSDL。

HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet("http://www.example.com/" + URL);
HttpResponse response = httpClient.execute(httpGet, localContext);
于 2009-01-08T22:17:35.247 回答
60

确实,由于它的开销,SOAP 并不是与移动设备进行数据交换的最佳选择。但是,您可能会发现自己无法控制服务器输出的格式。

所以,如果你必须坚持使用 SOAP,这里有一个为 Android 打补丁的 kSOAP2 库:
http ://code.google.com/p/ksoap2-android/

于 2009-10-10T10:57:57.990 回答
31

要从移动设备(尤其是 Android 手机)调用 Web 服务,我使用了一种非常简单的方法。我没有使用任何 Web 服务客户端 API 来尝试调用 Web 服务。我的方法如下拨打电话。

  1. 使用 Java 标准 API 创建一个简单的 HTTP 连接 HttpURLConnection
  2. 形成一个 SOAP 请求。(您可以借助 SOAPUI 来发出 SOAP 请求。)
  3. 将 doOutPut 标志设置为 true。
  4. 设置 HTTP 标头值,例如内容长度、内容类型和用户代理。不要忘记设置 Content-length 值,因为它是强制性的。
  5. 将整个 SOAP 请求写入输出流。
  6. 调用该方法建立连接并接收响应(在我的情况下,我使用了 getResonseCode)。
  7. 如果您收到的响应代码为
    1. 这意味着您成功调用了Web服务。
  8. 现在在同一个 HTTP 连接上获取一个输入流并接收字符串对象。此字符串对象是一个 SOAP 响应。
  9. 如果响应代码不是 200,则ErrorInput在同一个 HTTPobject 上获取一个流并接收错误(如果有)。
  10. 使用 SAXParser(在我的例子中)或 DOMParaser 或任何其他解析机制解析收到的响应。

我已经为安卓手机实现了这个程序,并且运行成功。即使响应超过 700 KB,我也能够解析它。

于 2010-02-04T10:55:25.403 回答
30

SOAP 是一种不适合在 Android(或一般的移动设备)上使用的技术,因为它需要处理/解析开销。REST 服务是一种更轻量级的解决方案,这就是我的建议。Android 带有一个 SAX 解析器,使用起来相当简单。如果您绝对需要在移动设备上处理/解析 SOAP,那么我为您感到抱歉,我能提供的最佳建议就是不要使用 SOAP。

于 2009-01-12T17:04:32.017 回答
24

大约一年前,我正在阅读这个线程,试图弄清楚如何在 Android 上进行 SOAP 调用 - 使用 HttpClient 构建我自己的建议导致我为 Android 构建了自己的 SOAP 库:

冰皂

基本上,它允许您构建信封以通过简单的 Java API 发送,然后自动将它们解析为您通过 XPath 定义的对象......例如:

<Dictionary>
    <Id></Id>
    <Name></Name>
</Dictionary>

变成:

@XMLObject("//Dictionary")
public class Dictionary {
    @XMLField("Id")
    private String id;

    @XMLField("Name")
    private String name;
}

我将它用于我自己的项目,但我认为它可能对其他人有所帮助,因此我花了一些时间将其分离出来并记录下来。如果你的一些可怜的灵魂在谷歌搜索“SOAP Android”时偶然发现了这个线程,我真的很喜欢它,他们可以试一试并获得一些好处。

于 2012-01-29T11:56:00.133 回答
24

不要忘记在您的项目中添加 ksoap2.jar 并在 AndroidManifest 文件中添加 INTERNET 权限

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class WebserviceActivity extends Activity {

    private static final String NAMESPACE = "https://api.authorize.net/soap/v1/";
    private static final String URL ="https://apitest.authorize.net/soap/v1/Service.asmx?wsdl"; 
    private static final String SOAP_ACTION = "https://api.authorize.net/soap/v1/AuthenticateTest";
    private static final String METHOD_NAME = "AuthenticateTest";
    private TextView lblResult;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        lblResult = (TextView) findViewById(R.id.tv);

        SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); 
        request.addProperty("name","44vmMAYrhjfhj66fhJN");
        request.addProperty("transactionKey","9MDQ7fghjghjh53H48k7e7n");
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); 
        envelope.setOutputSoapObject(request);
        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
        try {
            androidHttpTransport.call(SOAP_ACTION, envelope);

            //SoapPrimitive  resultsRequestSOAP = (SoapPrimitive) envelope.getResponse();
            // SoapPrimitive  resultsRequestSOAP = (SoapPrimitive) envelope.getResponse();
            SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;


            lblResult.setText(resultsRequestSOAP.toString());
            System.out.println("Response::"+resultsRequestSOAP.toString());


        } catch (Exception e) {
            System.out.println("Error"+e);
        }

    }
}
于 2012-06-07T06:50:43.750 回答
21

我与 KSOAP 幽会;我选择了一种更简单的方法。

给定一个 WSDL 文件,为每个请求创建 SOAP 请求模板(例如:使用 SOAP UI),然后替换要在代码中传递的值。使用 DefaultHttpClient 实例将此数据发布到服务端点并获取响应流。使用 XML Pull 解析器解析响应流。

于 2009-12-21T16:10:07.703 回答
18

你可以看看WSClient++

于 2010-07-15T08:52:51.770 回答
16

我为 Android 平台创建了一个新的 SOAP 客户端。它使用的是 JAX-WS 生成的接口,但到目前为止它只是一个概念验证。

如果您有兴趣,请尝试该示例和/或在AndroidSOAP上观看源代码。

于 2010-10-19T15:42:44.500 回答
15

如果可以,请选择 JSON。Android 自带完整的 org.json 包

于 2009-12-23T15:14:28.677 回答
14

调用ksoap2方法。它工作得很好。

设置详细信息,例如

private static String mNAMESPACE=null;
private static String mURL=null;
public static Context context=null;
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(Request);

envelope.addMapping(mNAMESPACE, "UserCredentials",new UserCredendtials().getClass());
AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(mURL);

然后得到结果

androidHttpTransport.call(SOAP_ACTION, envelope);
result = (SoapPrimitive)envelope.getResponse();
于 2011-05-18T07:19:21.577 回答
13

我希望从 Android 调用网络服务有所帮助。

于 2010-04-25T01:06:14.620 回答
11

几个月前,我在 j2ee 应用程序中使用 jax-ws Web 服务,我们使用CXF wsdl2java从 WSDL 文件生成 WS 客户端存根,并使用这些客户端存根使用 Web 服务。几周前,当我试图在 android 平台上以同样的方式使用 web 服务时,我做不到,因为 android jar 中没有所有的“jax-ws”支持类。那个时候我没有找到任何这样的工具(如果我没有有效地用谷歌搜索的话)来满足我的要求——

  • 从 WSDL 获取客户端存根。
  • 并使用一些参数(java 业务请求对象)调用服务。
  • 获取响应业务对象。

因此,我开发了自己的Android SOAP 客户端生成工具。您必须按照以下步骤操作:

  • 从 WSDL 获取 WS Client Stub,把它放到你的项目中。
  • 说一些服务“ComplexOperationService”,实例化服务,获取端点端口并调用服务方法,并从 Web 服务获取响应:

例如:

ComplexOperationService service = new ComplexOperationService( );
ComplexOperation port= service.getComplexOperationPort();    
SomeComplexRequest request = --Get some complex request----;    
SomeComplexResp resp = port.operate( request  );
  • 您不需要关心服务类/请求/响应类或任何其他类和方法,因为您知道它们都是从 WSDL 生成的。
  • 当然,您不需要知道肥皂动作/信封/命名空间等。只需像我们开发人员一样调用该方法即可。
于 2012-05-10T15:53:29.197 回答
9

我相信您可以使用Axis制作一个小 SOAP 客户端。轴安装说明

于 2008-11-18T17:49:15.560 回答
8

我认为从 Android 应用程序调用 SOAP Web 服务 会对您有很大帮助。

于 2011-01-28T10:35:53.107 回答
6

如果您可以使用 JSON,则在使用 PHP 服务器和 Android 手机客户端开发应用程序服务中有一份白皮书、一个视频和示例代码。

于 2011-04-24T10:07:38.610 回答
6

按照 SOAP 方法执行这些步骤

从 WSDL 文件中,

  • 为每个请求创建 SOAP 请求模板。

  • 然后替换要在代码中传递的值。

  • 使用 DefaultHttpClient 实例将此数据发布到服务端点。

  • 获取响应流,最后

  • 使用 XML Pull 解析器解析响应流。

于 2012-06-01T09:20:04.970 回答
6

对我来说,最简单的方法是使用好的工具来生成所有必需的类。我个人使用这个网站:

http://easywsdl.com/

它支持相当复杂的 Web 服务并使用 ksoap2。

于 2013-11-13T06:54:42.860 回答
5

如果您在调用 android 中的 Web 服务时遇到问题,那么您可以使用下面的代码来调用 Web 服务并获得响应。确保您的 Web 服务以数据表格式返回响应。如果您使用SQL Server数据库中的数据,此代码将为您提供帮助。如果您使用MYSQL,您需要更改一件事,只需用 DocumentElement 替换 句子中单词NewDataSetobj2=(SoapObject) obj1.getProperty("NewDataSet");

void callWebService(){ 

private static final String NAMESPACE = "http://tempuri.org/"; // for wsdl it may be package name i.e http://package_name
private static final String URL = "http://localhost/sample/services/MyService?wsdl";
// you can use IP address instead of localhost
private static final String METHOD_NAME = "Function_Name";
private static final String SOAP_ACTION = "urn:" + METHOD_NAME;

    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
    request.addProperty("parm_name", prm_value);// Parameter for Method
    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    envelope.dotNet = true;// **If your Webservice in .net otherwise remove it**
    envelope.setOutputSoapObject(request);
    HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

    try {
        androidHttpTransport.call(SOAP_ACTION, envelope);// call the eb service
                                                                                                         // Method
    } catch (Exception e) {
        e.printStackTrace();
    }

    // Next task is to get Response and format that response
    SoapObject obj, obj1, obj2, obj3;
    obj = (SoapObject) envelope.getResponse();
    obj1 = (SoapObject) obj.getProperty("diffgram");
    obj2 = (SoapObject) obj1.getProperty("NewDataSet");

    for (int i = 0; i < obj2.getPropertyCount(); i++) { 
// the method getPropertyCount() and  return the number of rows
            obj3 = (SoapObject) obj2.getProperty(i);
            obj3.getProperty(0).toString();// value of column 1
            obj3.getProperty(1).toString();// value of column 2
            // like that you will get value from each column
        }
    }

如果您对此有任何问题,可以写信给我。

于 2012-05-21T08:20:36.847 回答
5

我建议查看一个对我有很大帮助的非常有用的工具。负责那个项目的人也非常乐于助人。www.wsdl2code.com/

于 2013-05-28T06:58:45.033 回答
4

这是一个在 android 中使用 SOAP Web 服务的工作示例。

**注意 ::***不要忘记在您的项目中添加 ksoap2.jar 并在 AndroidManifest 文件中添加 INTERNET 权限*

public final String WSDL_TARGET_NAMESPACE = "http://tempuri.org/";
public final String METHOD_NAME = "FahrenheitToCelsius";
public final String PROPERTY_NAME = "Fahrenheit";
public final String SOAP_ACTION = "http://tempuri.org/FahrenheitToCelsius";
public final String SOAP_ADDRESS = "http://www.w3schools.com/webservices/tempconvert.asmx";


private class TestAsynk extends AsyncTask<String, Void, String> {

    @Override
    protected void onPostExecute(String result) {

        super.onPostExecute(result);
        Toast.makeText(getApplicationContext(),
                String.format("%.2f", Float.parseFloat(result)),
                Toast.LENGTH_SHORT).show();
    }

    @Override
    protected String doInBackground(String... params) {
        SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE,
                METHOD_NAME);
        request.addProperty(PROPERTY_NAME, params[0]);

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                SoapEnvelope.VER11);
        envelope.dotNet = true;

        envelope.setOutputSoapObject(request);

        HttpTransportSE androidHttpTransport = new HttpTransportSE(
                SOAP_ADDRESS);
        Object response = null;
        try {

            androidHttpTransport.call(SOAP_ACTION, envelope);
            response = envelope.getResponse();
            Log.e("Object response", response.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return response.toString();
    }
}
于 2013-07-30T05:33:26.227 回答
4

请下载并使用您的项目添加 SOAP 库文件文件名:ksoap2-android-assembly-3.4.0-jar-with-dependencies

清理应用程序,然后启动程序

这是 SOAP 服务调用的代码

    String SOAP_ACTION = "YOUR_ACTION_NAME";
    String METHOD_NAME = "YOUR_METHOD_NAME";
    String NAMESPACE = "YOUR_NAME_SPACE";
    String URL = "YOUR_URL";
    SoapPrimitive resultString = null;

    try {
        SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME);
        addPropertyForSOAP(Request);

        SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        soapEnvelope.dotNet = true;
        soapEnvelope.setOutputSoapObject(Request);

        HttpTransportSE transport = new HttpTransportSE(URL);

        transport.call(SOAP_ACTION, soapEnvelope);
        resultString = (SoapPrimitive) soapEnvelope.getResponse();

        Log.i("SOAP Result", "Result Celsius: " + resultString);
    } catch (Exception ex) {
        Log.e("SOAP Result", "Error: " + ex.getMessage());
    }
    if(resultString != null) {
        return resultString.toString();
    }
    else{
        return "error";
    }

结果可能是 JSONObject 或 JSONArray 或 String

为了您更好的参考, https://trinitytuts.com/load-data-from-soap-web-service-in-android-application/

谢谢。

于 2015-12-08T13:02:13.783 回答
3

您可以使用某些标头通过 http 执行肥皂调用作为 post。我在没有像 ksoap2 这样的额外库的情况下解决了这个问题 这是从肥皂服务获取订单的实时代码

private static HashMap<String,String> mHeaders = new HashMap<>();

static {
    mHeaders.put("Accept-Encoding","gzip,deflate");
    mHeaders.put("Content-Type", "application/soap+xml");
    mHeaders.put("Host", "35.15.85.55:8080");
    mHeaders.put("Connection", "Keep-Alive");
    mHeaders.put("User-Agent","AndroidApp");
    mHeaders.put("Authorization","Basic Q2xpZW50NTkzMzppMjR3s2U="); // optional
}public final static InputStream receiveCurrentShipments(String stringUrlShipments)
{
    int status=0;
    String xmlstring= "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:ser=\"http://35.15.85.55:8080/ServiceTransfer\">\n" +
            "   <soap:Header/>\n" +
            "   <soap:Body>\n" +
            "      <ser:GetAllOrdersOfShipment>\n" +
            "         <ser:CodeOfBranch></ser:CodeOfBranch>\n" +
            "      </ser:GetAllOrdersOfShipment>\n" +
            "   </soap:Body>\n" +
            "</soap:Envelope>";
    StringBuffer chaine = new StringBuffer("");

    HttpURLConnection connection = null;
    try {
        URL url = new URL(stringUrlShipments);
        connection = (HttpURLConnection) url.openConnection();
        connection.setRequestProperty("Content-Length", xmlstring.getBytes().length + "");
        connection.setRequestProperty("SOAPAction", "http://35.15.85.55:8080/ServiceTransfer/GetAllOrdersOfShipment");

        for(Map.Entry<String, String> entry : mHeaders.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            connection.setRequestProperty(key,value);

        }

        connection.setRequestMethod("POST");
        connection.setDoInput(true);

        OutputStream outputStream = connection.getOutputStream();
        outputStream.write(xmlstring.getBytes("UTF-8"));
        outputStream.close();

        connection.connect();
        status = connection.getResponseCode();
    } catch (ProtocolException e) {
        e.printStackTrace();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {

        Log.i("HTTP Client", "HTTP status code : " + status);
    }

    InputStream inputStream = null;
    try {
        inputStream = connection.getInputStream();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return inputStream;
}
于 2016-08-19T05:42:08.570 回答
2

要从 android 调用 SOAP Web 服务,请尝试使用此客户端

不要忘记在您的 java 构建路径中添加 ksoap2-android.jar

public class WsClient {
    private static final String SOAP_ACTION = "somme";
    private static final String OPERATION_NAME = "somme";
    private static final String WSDL_TARGET_NAMESPACE = "http://example.ws";
    private static final String SOAP_ADDRESS = "http://192.168.1.2:8080/axis2/services/Calculatrice?wsdl";

    public String caclculerSomme() {

        String res = null;
        SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE,
                OPERATION_NAME);
        request.addProperty("a", "5");
        request.addProperty("b", "2");

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.setOutputSoapObject(request);
        HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);

        try {
            httpTransport.call(SOAP_ACTION, envelope);
            String result = envelope.getResponse().toString();
            res = result;
            System.out.println("############# resull is :" + result);
        } catch (Exception exception) {
            System.out.println("########### ERRER" + exception.getMessage());
        }

        return res;
    }
}
于 2012-06-07T00:13:21.810 回答
1

添加肥皂 Libaray( ksoap2-android-assembly-3.2.0-jar-with-dependencies.jar):

公共静态字符串 Fn_Confirm_CollectMoney_Approval(

        HashMap < String, String > str1,
        HashMap < String, String > str2,
        HashMap < String, String > str3) {

    Object response = null;
    String METHOD_NAME = "CollectMoney";
    String NAMESPACE = "http://xxx/yyy/xxx";
    String URL = "http://www.w3schools.com/webservices/tempconvert.asmx";
    String SOAP_ACTION = "";

    try {

        SoapObject RequestParent = new SoapObject(NAMESPACE, METHOD_NAME);

        SoapObject Request1 = new SoapObject(NAMESPACE, "req");

        PropertyInfo pi = new PropertyInfo();

        Set mapSet1 = (Set) str1.entrySet();

        Iterator mapIterator1 = mapSet1.iterator();

        while (mapIterator1.hasNext()) {

            Map.Entry mapEntry = (Map.Entry) mapIterator1.next();

            String keyValue = (String) mapEntry.getKey();

            String value = (String) mapEntry.getValue();

            pi = new PropertyInfo();

            pi.setNamespace("java:com.xxx");

            pi.setName(keyValue);

            pi.setValue(value);

            Request1.addProperty(pi);
        }

        mapSet1 = (Set) str3.entrySet();

        mapIterator1 = mapSet1.iterator();

        while (mapIterator1.hasNext()) {

            Map.Entry mapEntry = (Map.Entry) mapIterator1.next();

            // getKey Method of HashMap access a key of map
            String keyValue = (String) mapEntry.getKey();

            // getValue method returns corresponding key's value
            String value = (String) mapEntry.getValue();

            pi = new PropertyInfo();

            pi.setNamespace("java:com.xxx");

            pi.setName(keyValue);

            pi.setValue(value);

            Request1.addProperty(pi);
        }

        SoapObject HeaderRequest = new SoapObject(NAMESPACE, "XXX");

        Set mapSet = (Set) str2.entrySet();

        Iterator mapIterator = mapSet.iterator();

        while (mapIterator.hasNext()) {

            Map.Entry mapEntry = (Map.Entry) mapIterator.next();

            // getKey Method of HashMap access a key of map
            String keyValue = (String) mapEntry.getKey();

            // getValue method returns corresponding key's value
            String value = (String) mapEntry.getValue();

            pi = new PropertyInfo();

            pi.setNamespace("java:com.xxx");

            pi.setName(keyValue);

            pi.setValue(value);

            HeaderRequest.addProperty(pi);
        }

        Request1.addSoapObject(HeaderRequest);

        RequestParent.addSoapObject(Request1);

        SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(
                SoapEnvelope.VER10);

        soapEnvelope.dotNet = false;

        soapEnvelope.setOutputSoapObject(RequestParent);

        HttpTransportSE transport = new HttpTransportSE(URL, 120000);

        transport.debug = true;

        transport.call(SOAP_ACTION, soapEnvelope);

        response = (Object) soapEnvelope.getResponse();

        int cols = ((SoapObject) response).getPropertyCount();

        Object objectResponse = (Object) ((SoapObject) response)
                .getProperty("Resp");

        SoapObject subObject_Resp = (SoapObject) objectResponse;


        modelObject = new ResposeXmlModel();

        String MsgId = subObject_Resp.getProperty("MsgId").toString();


        modelObject.setMsgId(MsgId);

        String OrgId = subObject_Resp.getProperty("OrgId").toString();


        modelObject.setOrgId(OrgId);

        String ResCode = subObject_Resp.getProperty("ResCode").toString();


        modelObject.setResCode(ResCode);

        String ResDesc = subObject_Resp.getProperty("ResDesc").toString();


        modelObject.setResDesc(ResDesc);

        String TimeStamp = subObject_Resp.getProperty("TimeStamp")
                .toString();


        modelObject.setTimestamp(ResDesc);

        return response.toString();

    } catch (Exception ex) {

        ex.printStackTrace();

        return null;
    }

}
于 2016-05-30T11:27:41.577 回答