Web Services 如何从服务器端模拟复杂的REST调用?

amrnrhlw  于 2022-11-15  发布在  其他
关注(0)|答案(2)|浏览(172)

在使用大量使用REST服务的JavaScript时--包括使用GET、PUT、POST、DELETES等vocab;我发现很难模拟服务器端,这样前端开发就可以独立进行(后端)。
有时候捕获多步数据也很有用,这样我们甚至可以帮助重现整个REST链(或者从这些链触发的与前端相关的bug)
我可以使用什么工具来模拟REST调用,特别是有状态的调用?(例如,如果我对某个资源执行PUT,我希望它的下一个GET会以某种方式发生变化)
我试过SOAPUI 4.0.1,它的REST模拟令人失望。另外,我的需要超出了单一状态模拟(任何人都可以用静态.json文件完成)。我需要做状态转换类型的模拟;最好使用Content-Range标题。
有没有人?

zbsbpyhn

zbsbpyhn1#

实际上,我创建了自己的Java REST Mock Engine,它基本上可以模拟任何响应。只要您可以手工或剪切粘贴一个模拟整个http响应的文本文件,就可以使用我的解决方案来模拟服务。
下面是servlet:

package com.mockrest.debug;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class MockGridData
 */
public class MockRest extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public MockRest() {
        super();
        // TODO Auto-generated constructor stub
    }

    @Override
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {
        sub:{
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)res;
            String setdata = request.getParameter("__setdata");
            if (setdata!=null && setdata.length()>0){
                System.err.println("Setting Data...");
                HttpSession sess = request.getSession(true);
                String data = "/"+request.getParameter("__setdata");
                sess.setAttribute("data", data);
                try{
                    InputStream is = getServletContext().getResourceAsStream(data);
                    if (is!=null){
                        is.close();
                        response.getWriter().write("Successfully pointed next REST call to:"+data);
                    }
                    else{
                        response.sendError(500, "Cannot find resource:"+data);
                    }
                }
                catch (IOException ioe){
                    response.sendError(500, Arrays.deepToString(ioe.getStackTrace()));
                }

            }
            else{
                System.err.println("Fetching Data...");
                HttpSession sess = request.getSession(false);
                if (sess==null || sess.getAttribute("data")==null){
                    response.sendError(500,"Session invalid or no Previous Data Set!");
                }
                String rsrc = (String)sess.getAttribute("data");
                System.err.println("Resource Being used:"+rsrc);
                InputStream is = getServletContext().getResourceAsStream(rsrc);
                if (is!=null){
                    String statusline = readLine(is);
                    Pattern statusPat = Pattern.compile("^HTTP/1.1 ([0-9]+) (.*)$");
                    Matcher m = statusPat.matcher(statusline);
                    if (m!=null && m.matches()){
                        int status = Integer.valueOf(m.group(1));
                        response.setStatus(status, m.group(2));
                    }
                    else{
                        throw new ServletException("Bad input file: status line parsing failed, got this as status line:"+statusline);
                    }
                    String line;
                    Pattern httpHeaderPat = Pattern.compile("^([^:]+): (.*)$");
                    while ((line=readLine(is))!=null){
                        if (line.length()==0){
                            // end of headers
                            break;
                        }
                        Matcher m2 = httpHeaderPat.matcher(line);
                        if (m2!=null && m2.matches()){
                            response.setHeader(m2.group(1), m2.group(2));
                        }
                    }
                    OutputStream os = response.getOutputStream();
                    byte[] buf = new byte[1024];
                    int size;
                    while ((size=is.read(buf))>0){
                        os.write(buf, 0, size);
                    }
                    os.flush();
                }
            }
        }
    }

    private String readLine(InputStream is) throws IOException {
        StringBuffer sb = new StringBuffer();
        char c;
        while ((c=(char)is.read())!='\n'){
            sb.append(c);
        }
        if (sb.charAt(sb.length()-1) == '\r'){
            sb.deleteCharAt(sb.length()-1);
        }
        return sb.toString();
    }

}

要配置它,请将预建的响应文件放在WebContent文件夹中。我通常以.http扩展名结束这些文件。
下面是一个init.http文件示例。假设我们将此文件放在WebContent中名为data的文件夹中:

HTTP/1.1 200 OK
Date: Wed, 26 Oct 2011 18:31:45 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Content-Range: items 0-1/2
Content-Length: 385
Cache-Control: private
Content-Type: application/json

[
  {
    "id": "249F0",
    "field1": " Global",
    "displaystartdate": "2007-10-20",
    "displayenddate": "2012-10-20",
    "status": "Major Delay",
    "children": true
  },
  {
    "id": "962581",
    "field2": "Europe",
    "displaystartdate": "2007-10-20",
    "displayenddate": "2012-10-20",
    "status": "Major Delay",
    "children": true
  }
]

标题必须用空行(没有空格,nada)与正文分开。熟悉http的人会注意到这是一个纯粹的http响应。这是故意的。
您可以使用此工具模拟您希望响应具有的任何http标头;甚至使用不同的服务器头进行响应(在我的示例中,我模拟了假装为IIS6.0的响应);、或不同HTTP状态代码等。
从浏览器/javascript调用它;首先用以下物质灌注:

http://yourserver/yourweb/MockGridData?__setdata=data/init.http

然后在javascript或REST AJAX 调用中,如果它转到

http://yourserver/yourweb/MockGridData

使用任何方法或参数;它将获得您以前创建的http响应;甚至下至内容范围;缓存标头;如果您需要后续的 AJAX 调用返回其他内容,只需再次使用__setdata调用即可。我建议您在Web应用程序中设置一些按钮来执行显式的状态转换。
假设一切都已设置,对于模拟的REST链,开发人员可以执行以下操作:
1.调用

http://yourserver/yourweb/MockGridData?__setdata=data/init.http

1.运行一个javascript模块,该模块将导致调用(例如,使用GET)

http://yourserver/yourweb/MockGridData

1.单击按钮,然后执行以下操作:

http://yourserver/yourweb/MockGridData?__setdata=data/step1.http

1.运行另一个javascript步骤,该步骤将导致调用(例如,使用PUT)

http://yourserver/yourweb/MockGridData

1.单击另一个按钮,然后执行以下操作:

http://yourserver/yourweb/MockGridData?__setdata=data/step2.http

1.运行另一个javascript步骤,该步骤将导致调用(例如,使用GET)

http://yourserver/yourweb/MockGridData

但这次预期结果与#4不同。
这甚至应该与二进制和gzip的响应工作,但我还没有测试。

7tofc5zh

7tofc5zh2#

下面是另一个自制的休息模拟工具:https://github.com/mkotsur/restito

相关问题