我正在为我们的应用程序开发一个新的RESTful Web服务。
当对某些实体执行GET时,客户端可以请求实体的内容。如果他们想添加一些参数(例如排序列表),可以在查询字符串中添加这些参数。
或者,我希望人们能够在请求主体中指定这些参数。HTTP/1.1似乎并没有明确禁止这一点。这将允许他们指定更多信息,可能会更容易指定复杂的XML请求。
我的问题:
这完全是个好主意吗?HTTP客户端在GET请求中使用请求体时会遇到问题吗?
https://www.rfc-editor.org/rfc/rfc2616
创建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);
}
}
}
罗伊·菲尔丁(Roy Fielding)关于在GET请求中包含身体的评论。
对换句话说,任何HTTP请求消息都允许包含消息体,因此必须考虑到这一点来解析消息。然而,GET的服务器语义受到限制,使得主体(如果有的话)对请求没有语义意义。解析的需求与方法语义的需求是分开的。所以,是的,你可以用GET发送一个身体,但不,这样做从来都没有用。这是HTTP/1.1分层设计的一部分,一旦规范被划分(正在进行中),分层设计将再次变得清晰。……罗伊
是的,您可以用GET发送请求体,但它应该没有任何意义。如果您通过在服务器上解析它并根据其内容更改响应来赋予其含义,那么您将忽略HTTP/1.1规范第4.3节中的建议:
…如果请求方法不包含实体体的定义语义,则在处理请求时应忽略消息体。
以及HTTP/1.1规范第9.3节中GET方法的描述:
GET方法意味着检索请求URI标识的任何信息([…])。
其声明请求主体不是GET请求中的资源标识的一部分,而是请求URI。
使现代化
被称为“HTTP/1.1规范”的RFC2616现在已经过时。2014年,它被RFC7230-7237取代。引号“处理请求时应忽略消息正文”已删除。现在只是“请求消息框架独立于方法语义,即使该方法没有定义消息体的任何用途”第二个引号“GET方法意味着检索任何信息……由请求URI标识”被删除。-来自评论
根据HTTP 1.1 2014规范:
GET请求消息中的有效负载没有定义的语义;在GET请求上发送有效负载主体可能会导致一些现有实现拒绝该请求。