我正在为我们的应用程序开发一个新的RESTful Web服务。

当对某些实体执行GET时,客户端可以请求实体的内容。如果他们想添加一些参数(例如排序列表),可以在查询字符串中添加这些参数。

或者,我希望人们能够在请求主体中指定这些参数。HTTP/1.1似乎并没有明确禁止这一点。这将允许他们指定更多信息,可能会更容易指定复杂的XML请求。

我的问题:

这完全是个好主意吗?HTTP客户端在GET请求中使用请求体时会遇到问题吗?

https://www.rfc-editor.org/rfc/rfc2616


当前回答

如果您尝试利用缓存,可能会遇到问题。代理不会在GET主体中查看参数是否对响应有影响。

其他回答

我不建议这样做,这违背了标准做法,也没有提供那么多回报。您希望保留内容的正文,而不是选项。

REST作为协议不支持OOP,Get方法就是证明。作为解决方案,您可以将DTO序列化为JSON,然后创建查询字符串。在服务器端,您将能够将查询字符串反序列化为DTO。

看看:

ServiceStack中基于消息的设计使用WCF构建基于RESTful消息的Web服务

基于消息的方法可以帮助您解决Get方法的限制。您可以将任何DTO作为请求主体发送

Nelibur web服务框架提供了您可以使用的功能

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D

创建Requestfactory类

import java.net.URI;

import javax.annotation.PostConstruct;

import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class RequestFactory {
    private RestTemplate restTemplate = new RestTemplate();

    @PostConstruct
    public void init() {
        this.restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestWithBodyFactory());
    }

    private static final class HttpComponentsClientHttpRequestWithBodyFactory extends HttpComponentsClientHttpRequestFactory {
        @Override
        protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
            if (httpMethod == HttpMethod.GET) {
                return new HttpGetRequestWithEntity(uri);
            }
            return super.createHttpUriRequest(httpMethod, uri);
        }
    }

    private static final class HttpGetRequestWithEntity extends HttpEntityEnclosingRequestBase {
        public HttpGetRequestWithEntity(final URI uri) {
            super.setURI(uri);
        }

        @Override
        public String getMethod() {
            return HttpMethod.GET.name();
        }
    }

    public RestTemplate getRestTemplate() {
        return restTemplate;
    }
}

和@Autowired,这里是一个带有RequestBody的GET请求示例代码

 @RestController
 @RequestMapping("/v1/API")
public class APIServiceController {
    
    @Autowired
    private RequestFactory requestFactory;
    

    @RequestMapping(method = RequestMethod.GET, path = "/getData")
    public ResponseEntity<APIResponse> getLicenses(@RequestBody APIRequest2 APIRequest){
        APIResponse response = new APIResponse();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        Gson gson = new Gson();
        try {
            StringBuilder createPartUrl = new StringBuilder(PART_URL).append(PART_URL2);
            
            HttpEntity<String> entity = new HttpEntity<String>(gson.toJson(APIRequest),headers);
            ResponseEntity<APIResponse> storeViewResponse = requestFactory.getRestTemplate().exchange(createPartUrl.toString(), HttpMethod.GET, entity, APIResponse.class); //.getForObject(createLicenseUrl.toString(), APIResponse.class, entity);
    
            if(storeViewResponse.hasBody()) {
                response = storeViewResponse.getBody();
            }
            return new ResponseEntity<APIResponse>(response, HttpStatus.OK);
        }catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<APIResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
        }
        
    }
}

不符合base64编码的标头怎么办?“某些参数:sdfSD45fdg45/aS”

长度限制hm.你不能让POST处理区分含义吗?如果你想要像排序这样的简单参数,我不明白为什么这会是一个问题。我想你肯定担心。

Elasticsearch接受带有主体的GET请求。甚至似乎这是首选的方法:Elasticsearch指南

一些客户端库(如Ruby驱动程序)可以在开发模式下将cry命令记录到stdout,并且它广泛使用这种语法。