2017年2月3日 星期五

前端呼叫WebService、同源策略 ( WebService 五)

還是使用上一篇 Spring 架好的CXF
再新增一個 動態Web 專案


※使用JS呼叫

可看W3C官網複製

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
        <script type="text/javascript">
            function jsCallWebService() {
                const a = document.getElementById("account").value;
                const p = document.getElementById("password").value;
                const n1 = document.getElementById("num1").value;
                const n2 = document.getElementById("num2").value;
                var data = getData(a, p, n1, n2);
        
                const request = getXmlHttp();
                request.onreadystatechange = function() {
                    if (request.readyState == 4 && request.status == 200) {
                        var result = request.responseXML;
                        var rtn = result.getElementsByTagName("return")[0];
                        var vue = rtn.firstChild.data;
                        document.getElementById("ta").value = vue;
                    }
                };
    
                request.open("POST", "http://localhost:8080/SCXF/aaa/bbb/ccc", true);
                request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                request.send(data);
            }
    
            function getXmlHttp() {
                var xmlhttp;
                if (window.XMLHttpRequest) {
                    // code for modern browsers
                    xmlhttp = new XMLHttpRequest();
                } else {
                    // code for old IE browsers
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                return xmlhttp;
            }
    
            function getData(a, p, n1, n2){
                var d =
                    '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:test="http://test.hello/">' +
                        '<soapenv:Header>' +
                            '<login>' +
                                '<acc>' + a + '</acc>' +
                                '<pass>' + p + '</pass>' +
                            '</login>' +
                        '</soapenv:Header>' +
                        '<soapenv:Body>' +
                            '<test:add>' +
                                '<arg0>' + n1 + '</arg0>' +
                                '<arg1>' + n2 + '</arg1>' +
                            '</test:add>' +
                        '</soapenv:Body>' +
                    '</soapenv:Envelope>';
                return d;
            }
        </script>
    </head>
    
    <body>
        帳號: <input id="account" type="text" value="bruce" /><br />
        密碼: <input id="password" type="password" value="12345" /><br />
        參數1:<input id="num1" type="number" placeholder=0 /><br />
        參數2:<input id="num2" type="number" placeholder=0 /><br />
        <textarea id="ta"></textarea><br />
        <button onclick="jsCallWebService()">javascript AJAX call WebService</button>
    </body>
</html>

※getData方法我本來沒有提出來,run也是ok的,但提出來後出了「org.apache.cxf.binding.soap.SoapFault: Error reading XMLStreamReader: Unexpected character 'u' (code 117) in prolog; expected '<'」的錯
我試著將要傳的參數、帳密都寫死,然後不用「+」串接,也不換行,但還是出一樣的錯
最後我用一個變數來接,最後在return,就沒出錯了



※使用jQuery呼叫

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
        <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
        <script type="text/javascript">
            function jsCallWebService() {
                const a = document.getElementById("account").value;
                const p = document.getElementById("password").value;
                const n1 = document.getElementById("num1").value;
                const n2 = document.getElementById("num2").value;
                var data = getData(a, p, n1, n2);
                        
                $.post(
                    "http://localhost:8080/SCXF/aaa/bbb/ccc", 
                    data,
                    function(result) {
                        var rtn = result.getElementsByTagName("return")[0];
                        var vue = rtn.firstChild.data;
                        document.getElementById("ta").value = vue;
                    }
                );
    
                //     $.ajax({
                //         type: "POST",
                //         url: "http://localhost:8080/SCXF/aaa/bbb/ccc",
                //         data: data,
                //         success: function(result){
                //             var rtn = result.getElementsByTagName("return")[0];
                //             var vue = rtn.firstChild.data;
                //             document.getElementById("ta").value = vue;
                //         }
                //     });
            }
            
            function getData(a, p, n1, n2){
                var d =
                    '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:test="http://test.hello/">' +
                        '<soapenv:Header>' +
                            '<login>' +
                                '<acc>' + a + '</acc>' +
                                '<pass>' + p + '</pass>' +
                            '</login>' +
                        '</soapenv:Header>' +
                        '<soapenv:Body>' +
                            '<test:add>' +
                                '<arg0>' + n1 + '</arg0>' +
                                '<arg1>' + n2 + '</arg1>' +
                            '</test:add>' +
                        '</soapenv:Body>' +
                    '</soapenv:Envelope>';
                return d;
            }
        </script>
    </head>
    <body>
        帳號: <input id="account" type="text" value="bruce" /><br />
        密碼:<input id="password" type="password" value="12345" /><br />
        參數1:<input id="num1" type="number" placeholder=0 /><br />
        參數2:<input id="num2" type="number" placeholder=0 /><br />
        <textarea id="ta"></textarea><br />
        <button onclick="jsCallWebService()">javascript AJAX call WebService</button>
    </body>
</html>

※註解是比較麻煩的寫法



※同源策略

localhost:8080改成「IP:8080」雖然不會出錯,但回傳就不會將值取出來了,用JS和jQuery都一樣

.什麼是同源策略可參考Mozilla 官網,網址列可將「en-US」改成「zh-TW」或「zh-CN」
總之就是http://www.google.com:80 分成三個部分
1.「http://」是protocol,還有ftp、https…等
2.「www.google.com」 是域名
3.「:80」是port,沒有寫就是:80
只要以上三個部分一樣,就是同源
現在大部分的瀏覽器預設都將 localhost 和轉換過的 IP 認為是不同的

.同源策略又衍生了 JSONP、CORS 技術
也就是同源策略不包括一些特定的標籤、如<script>標籤…等,其他的標籤上一個Mozilla 連結有寫
JSONP只能用在GET請求;CORS沒這個問題,但要較新的瀏覽器才有支援

.瀏覽器可關閉同源策略,可參考這個網址
我改IE 11是有成功的,但Chrome沒成功
使用chrome指令時先切換到chrome安裝資料夾,如我的安裝在「C:\Program Files (x86)\Google\Chrome\Application」,裡面有一支執行檔叫 chrome.exe ,切到這裡下指令即可
不然就要設環境變數了



※用HttpURLConnection可使localhost和IP一樣

package servlet;
    
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
    
@WebServlet("/conn")
public class Connection extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String a = request.getParameter("account");
        String p = request.getParameter("password");
        String n1 = request.getParameter("number1");
        String n2 = request.getParameter("number2");
        System.out.println(a + ":" + p + ":" + n1 + ":" + n2);
    
        String data = 
            "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:test='http://test.hello/'>" +
                "<soapenv:Header>" + 
                    "<login>" + 
                        "<acc>" + a + "</acc>" + 
                        "<pass>" + p + "</pass>" + 
                    "</login>"
                + "</soapenv:Header>" + 
                "<soapenv:Body>" + 
                    "<test:add>" + 
                        "<arg0>" + n1 + "</arg0>" + 
                        "<arg1>" + n2 + "</arg1>" + 
                    "</test:add>" + 
                "</soapenv:Body>" + 
            "</soapenv:Envelope>";
    
        URL url = new URL("http://192.168.0.10:8080/SCXF/aaa/bbb/ccc");
    
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");// 預設是GET
        connection.setDoOutput(true);// 往server端寫資料,預設是false
        connection.setDoInput(true);// 接收server端的資料,預設是true,所以可不寫
        connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
    
        // 向server端寫資料
        OutputStream out = connection.getOutputStream();
        out.write(data.getBytes("UTF-8"));
        out.close();
    
        int responseCode = connection.getResponseCode();
        if (responseCode == 200) {
            // 接收server端回傳的資料
            InputStream in = connection.getInputStream();
            System.out.println("in長度: " + in.available());
    
            // 將server端的資料給瀏覽器
            // 如給text/xml,那jQuery的dataType也必須是xml;給text/text,那jQuery的dataType也必須是text
            response.setContentType("text/xml;charset=UTF-8");
            ServletOutputStream sout = response.getOutputStream();
    
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                sout.write(buffer, 0, len);
            }
            sout.flush();
            in.close();
            sout.close();
        }
    }
}


※前端

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
        <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
        <script type="text/javascript">
            function jsCallWebService() {
                $.post(
                    "conn",
                    {
                        account : $('#account').val(),
                        password : $('#password').val(),
                        number1 : $('#num1').val(),
                        number2 : $('#num2').val()
                    },
                    function(result) {
                        // var vue = $(result).find('return').text();
                        var rtn = result.getElementsByTagName("return")[0];
                        var vue = rtn.firstChild.data;
                        document.getElementById("ta").value = vue;
                    },
                    'xml'
                );
    
                //     $.ajax({
                //         type: "POST",
                //         url: "conn",
                //         data: {
                //             account : $('#account').val(),
                //             password : $('#password').val(),
                //             number1 : $('#num1').val(),
                //             number2 : $('#num2').val()
                //         },
                //         success: function(result){
                //            // var vue = $(result).find('return').text();
                //             var rtn = result.getElementsByTagName("return")[0];
                //             var vue = rtn.firstChild.data;
                //             document.getElementById("ta").value = vue;
                //         },
                //         dataType:'xml'
                //     });
            }
        </script>
    </head>
    
    <body>
        帳號: <input id="account" type="text" value="bruce" /><br />
        密碼: <input id="password" type="password" value="12345" /><br />
        參數1:<input id="num1" type="number" placeholder=0 /><br />
        參數2:<input id="num2" type="number" placeholder=0 /><br />
        <textarea id="ta"></textarea><br />
        <button onclick="jsCallWebService()">javascript AJAX call WebService</button>
    </body>
</html>

※$(result).find('return').text();使用在dataType是text時

※如果不寫dataType,jQuery預設是智能判斷,會找以下這5種 xml, json, script, text, html

沒有留言:

張貼留言