这是这个问题的重复,我理解这个问题的公认答案。但我想知道Netty是否有一些内置的功能来发送多部分响应消息。我遇到了这个类HttpPostRequestEncoder,它似乎可以完成创建多部分POST请求的工作。Response也有类似的东西吗?
很容易创建一个类似于HttpPostRequestEncoder的等效逻辑,并使其为响应工作,但我想知道也许Netty中已经有一些我不知道的东西。
我相信你是对的,没有这样的代码来做Multipart响应。但我认为它可以很容易地实现通过扩展HttpPostRequestEncoder添加一个类似的方法比finalizeRequest()来完成HttpResponse。
https://github.com/netty/netty/blob/1529ef1794e0a6654fa4334fd979b769d6940e61/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestEncoder.java L736
例如(未测试),添加以下方法可能至少是一个好的开始:
/**
* Finalize the response by preparing the Header in the response and returns the response ready to be sent.<br>
* Once finalized, no data must be added.<br>
* If the response does not need chunk (isChunked() == false), this response is the only object to send to the remote
* server.
*
* @return the response object (chunked or not according to size of body)
* @throws ErrorDataEncoderException
* if the encoding is in error or if the finalize were already done
*/
public HttpResponse finalizeResponse(HttpResponseStatus status) throws ErrorDataEncoderException {
// Finalize the multipartHttpDatas
if (!headerFinalized) {
if (isMultipart) {
InternalAttribute internal = new InternalAttribute(charset);
if (duringMixedMode) {
internal.addValue("rn--" + multipartMixedBoundary + "--");
}
internal.addValue("rn--" + multipartDataBoundary + "--rn");
multipartHttpDatas.add(internal);
multipartMixedBoundary = null;
currentFileUpload = null;
duringMixedMode = false;
globalBodySize += internal.size();
}
headerFinalized = true;
} else {
throw new ErrorDataEncoderException("Header already encoded");
}
HttpHeaders headers = request.headers();
List<String> contentTypes = headers.getAll(HttpHeaderNames.CONTENT_TYPE);
List<String> transferEncoding = headers.getAll(HttpHeaderNames.TRANSFER_ENCODING);
if (contentTypes != null) {
headers.remove(HttpHeaderNames.CONTENT_TYPE);
for (String contentType : contentTypes) {
// "multipart/form-data; boundary=--89421926422648"
String lowercased = contentType.toLowerCase();
if (lowercased.startsWith(HttpHeaderValues.MULTIPART_FORM_DATA.toString()) ||
lowercased.startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString())) {
// ignore
} else {
headers.add(HttpHeaderNames.CONTENT_TYPE, contentType);
}
}
}
if (isMultipart) {
String value = HttpHeaderValues.MULTIPART_FORM_DATA + "; " + HttpHeaderValues.BOUNDARY + '='
+ multipartDataBoundary;
headers.add(HttpHeaderNames.CONTENT_TYPE, value);
} else {
// Not multipart
headers.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED);
}
// Now consider size for chunk or not
long realSize = globalBodySize;
if (!isMultipart) {
realSize -= 1; // last '&' removed
}
iterator = multipartHttpDatas.listIterator();
headers.set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(realSize));
if (realSize > HttpPostBodyUtil.chunkSize || isMultipart) {
HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), status);
response.headers().add(headers);
isChunked = true;
if (transferEncoding != null) {
headers.remove(HttpHeaderNames.TRANSFER_ENCODING);
for (CharSequence v : transferEncoding) {
if (HttpHeaderValues.CHUNKED.contentEqualsIgnoreCase(v)) {
// ignore
} else {
headers.add(HttpHeaderNames.TRANSFER_ENCODING, v);
}
}
}
HttpUtil.setTransferEncodingChunked(response, true);
return response;
} else {
// get the only one body and set it to the request
HttpContent chunk = nextChunk();
DefaultFullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(), status, chunk.content());
response.headers().add(headers);
return response;
}
}
或者更简单:
public HttpResponse finalizeResponse(HttpResponseStatus status) throws ErrorDataEncoderException {
// Finalize the multipartHttpDatas
HttpRequest request = finalizeRequest();
if (request instanceof WrappedFullHttpRequest) {
DefaultFullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(), status,
((WrappedFullHttpRequest) request).content());
response.headers().add(request.headers());
return response;
} else {
HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), status);
response.headers().add(request.headers());
return response;
}
}