- Set Content-Type to application/json in jsp file
- HTTP-заголовки
- 6.2 User-Agent
- 6.3 Content-Type
- 6.4 Content-Length
- 6.5 Accept-Encoding
- REST-API Different Content-Type on Error Response
- 2 Answers 2
- HTTP Response content type different on HEAD request
- 1 Answer 1
- Adding Content-Type Headers to Java HTTP echo server
Set Content-Type to application/json in jsp file
The MIME type and character encoding the JSP file uses for the response it sends to the client. You can use any MIME type or character set that are valid for the JSP container. The default MIME type is text/html, and the default character set is ISO-8859-1.
Try this piece of code, it should work too
but this throws exception like java.lang.IllegalStateException: getOutputStream() has already been called for this response
make sure you do not output any single character to the client before calling setContentType(..) (otherwise the content type is already fixed before that). Especially pay attention to spaces or newlines after %>, e.g. write move the closing %> of the first line to the second line and start immediately with the next
Thanks, I could not used the page directive because I have to set a different content type according to some URL parameter. I will paste my code here since it’s something quite common with JSON:
response.setContentType("text/javascript"); > else < // Equivalent to: response.setContentType("application/json"); > [. ] String output = ""; if (callback != null) < output += callback + "("; >output += jsonObj.toString(); if (callback != null) < output += ");"; >%>
When callback is supplied, returns:
with content-type «text/javascript»
When callback is NOT supplied, returns:
with content-type «application/json»
HTTP-заголовки
Заголовки http-запроса – это фактически служебная информация для http-клиента и http-сервера. Но она очень важна, и, если ты в них совершенно не разбираешься, это частенько будет выходить тебе боком. Так что придется про них хотя бы почитать.
Все http-заголовки можно разделить на 4 основные группы:
# | Тип заголовка | Описание | Примечание |
---|---|---|---|
1 | General Headers | Общие заголовки | Используются в запросах и ответах |
2 | Request Headers | Заголовки запроса | Используются только в запросах |
3 | Response Headers | Заголовки ответа | Используются только в ответах |
4 | Entity Headers | Заголовки сущности | Сопровождают каждую сущность сообщения |
6.2 User-Agent
Самый важный и популярный заголовок – это User-Agent. Это специальная строка, которая описывает, какой клиент выполняет запрос на сервер. Такое себе имя клиента.
Часто сервер немного подстраивает свой ответ под запрашивающего. Например, если из запроса ясно, что запрос пришел из браузера мобильного телефона, то ему можно отдать мобильную версию HTML-страницы.
Спам-боты, менеджеры закачек и некоторые браузеры нередко шлют подложные User-Agent-строки, чтобы выдать себя за порядочных клиентов. Эта ситуация известна, как подмена или подделка пользовательского агента (user agent spoofing).
Например, мой User-Agent выглядит сейчас так:
Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0
В нем содержится информация о браузере, операционной системе и web-движке браузера.
6.3 Content-Type
Второй по популярности заголовок – это Content-Type. Он используется для того, чтобы определить MIME тип ресурса, который отдает сервер.
Еще на заре интернета для удобства были стандартизированы типы передаваемого медиа контента. Их называют Internet Media Types или сокращенно MimeTypes. Они делятся на 9 категорий:
Категория | Тип | Описание |
---|---|---|
audio | audio/mp4 | Аудио-файл в формате mp4 |
audio/aac | Аудио-файл в формате AAC | |
image | image/gif | Картинка gif |
image/jpeg | Картинка jpeg | |
image/png | Картинка png | |
text | text/css | CSS-файл |
text/html | HTML-файл | |
video | video/mpeg | Video-файл в формате mpeg |
video/webm | Video-файл в формате webm | |
video/3gpp | Video-файл в формате 3gpp | |
application | application/x-www-form-urlencoded | Закодированные данные |
application/zip | Архив zip | |
application/javascript | JavaScript | |
application/xml | XML |
Обычно сервер знает, какие данные он отдает. Но если ты самостоятельно генерируешь ответ сервера своим кодом, то тебе нужно указать тип ответа (Content-Type) твоего сервера.
6.4 Content-Length
Этот заголовок задает длину ответа сервера. Если по-простому, то размер отдаваемого файла. Вручную этот параметр устанавливать не нужно. Хотя бывает полезно посмотреть на то, что отдал сервер, если по каким-то причинам ответ пришел не весь.
6.5 Accept-Encoding
С помощью этого заголовка клиент может указать серверу, что он поддерживает различные алгоритмы сжатия контента. Таким образом сервер может сначала заархивировать контент, например, zip-архивом, затем переслать его клиенту и клиент сможет правильно восстановить оригинальный контент.
Преимущество архивации состоит в том, что чем меньше файл, тем быстрее передается. Минусы архивации – дополнительная нагрузка на клиент и на сервер. Архивация имеет смысл при передаче больших файлов и часто не имеет смысла при передаче маленьких.
Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5
Где deflate и gzip – это поддерживаемые алгоритмы сжатия данных, а q обозначает степень сжатия.
REST-API Different Content-Type on Error Response
Sounds for me like a really special REST question and couldn`t find related questions on this topic.
» When an error occurs in one of these services Spring-MVC will throw an HttpMediaTypeNotAcceptableException.» Can you elaborate this? What type of error do you mean?
Spring is comparing the «accept-header» with the response content-type. In a situation where «text/plain» was sent in accept-header and response content-type is incompatibel Spring will throw this exception (AbstractMessageConverterMethodProcessor)
2 Answers 2
I was facing the same issue, and I was having the exact same question about the REST best practices.
All the articles I read about handling errors in API responses use JSON. Example here.
I don’t think all of those APIs always wrap the data in JSON. Sometimes you just have to serve files, or text or non-json stuff. Also, I’ve stumbled upon RFC7807, which proposes a standard way to expose errors/probems with JSON format, even using its own content-type application/problem+json. Thus we can safely assume that using a different Content Type for HTTP 200 than for HTTP error codes is rather a good practice.
About how to do it with Spring Framework, it’s actually very simple. Once you’ve understood that the «produces =<>» is basically a declarative way to say that your response will be of some type, you can imagine that it’s also possible to programmatically set the type you want to return.
Here is an example API that should return application/octet-stream (a binary file).
@GetMapping(path = "/1/resources/hello", produces = ) public ResponseEntity getFile(@RequestParam(value = "charset", required = false, defaultValue = "UTF-8") String charset) < return ResponseEntity.ok().body(outputStream ->outputStream.write("Hello there".getBytes(Charset.forName(charset)))); >
When it works, it will return a file with the right content-type. Now, if you want to handle the error case (in this case, a wrong charset parameter), you can create an Exception Handler:
@ExceptionHandler(UnsupportedCharsetException.class) public ResponseEntity handleCharsetException(UnsupportedCharsetException e)
And now, the error case also works as expected:
GET http://localhost/1/resources/hello?charset=CRAP HTTP/1.1 400 Bad Request Connection: keep-alive Transfer-Encoding: chunked Content-Type: application/json;charset=UTF-8 Date: Mon, 25 Mar 2019 17:37:39 GMT
HTTP Response content type different on HEAD request
I am trying to achieve something if it is not text/html , but when I set the request method as HEAD , the content-type is shown as text/html . If I fire the same HEAD request using Poster or Postman , I see the content-type as image/jpeg . So what is it that makes the content-type change in case of this Java code?. Can someone please point out any mistake that I may have made? Note: I used this post as reference
I suppose your getting an HTML page which says «method not allowed» or some other error. You should probably add an «Accept» header and «User-Agent» header.
@hgoebl well, in that case, shouldn’t it have not given image/jpeg when tested using poster/postman ?
I’m not sure how many headers Postman is adding to your request which are not explicitly set by you. I suppose ‘User-Agent’ and ‘Accept’ could be one of them. Can you sniff the traffic (Fiddler, Wireshark)?
@hgoebl Thanks a lot, adding a User-Agent property to the request header solved the problem. Can you add that as an answer so that I can accept it!.
1 Answer 1
You should probably add an Accept header and/or User-Agent header.
Most web servers deliver different content depending on headers set by the client (e.g. web browser, Java HttpURLConnection, curl, . ). This is especially true for Accept , Accept-Encoding , Accept-Language , User-Agent , Cookie and Referer .
As an example, a web-server might refuse to deliver an image, if the Referer header does not link to an internal page. In your case, the web-server doesn’t deliver images if it seems like some robot is crawling it. So if you fake your request like if it’s coming from a web-browser, the server might deliver it.
When crawling web-sites, you should respect robots.txt (because you act like a robot). So strictly speaking you should be careful when faking User-Agent when doing a lot of requests or create a big business out of this. I don’t know how big web-sites react on such behavior, especially when someone by-passes there business.
Please don’t see this as a telling-off. I just wanted to point you to this, so you don’t run into trouble. Maybe it’s not a problem at all, YMMV.
Adding Content-Type Headers to Java HTTP echo server
I’m playing with HTTPservers and running into an issue. I need to add ContentType headers to the response, but when I do the client gets ERR_EMPTY_RESPONSE. If I remove:
headers.add("Content-Type", "text/html");
Then the server works fine, but I need to pass the CType headers for my app. What gives? How do I include Content-Type headers?
/* * EchoServer.java * * Accept an HTTP request and echo it back as the HTTP response. * * Copyright (c) 2005 Sun Microsystems, Inc * Copyright (c) 2008 Operational Dynamics Consulting, Pty Ltd * * The code in this file is made available to you by its authors under the * terms of the "GNU General Public Licence, version 2" See the LICENCE file * for the terms governing usage and redistribution. */ /* * This code is a simple derivation of the example in the package * documentation for com.sun.net.httpserver, as found in file * jdk/src/share/classes/com/sun/net/httpserver/package-info.java as shipped * with the openjdk 1.6 b08 code drop. Used under the terms of the GPLv2. */ import static java.net.HttpURLConnection.HTTP_OK; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.URLDecoder; import java.util.List; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange.*; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; /** * Echo the body of an HTTP request back as the HTTP response. This is merely * a simple exercise of the Secret Sun Web Server. As configured, the URL to * access it is http://localhost:8000/echo. * * @author Andrew Cowie */ public final class Test < public static void main(String[] args) throws IOException < final InetSocketAddress addr; final HttpServer server; addr = new InetSocketAddress(8000); server = HttpServer.create(addr, 10); server.createContext("/echo", new EchoHandler()); server.start(); >> class EchoHandler implements HttpHandler < public void handle(HttpExchange t) throws IOException < final InputStream is; final OutputStream os; StringBuilder buf; int b; final String request, response; buf = new StringBuilder(); /* * Get the request body and decode it. Regardless of what you are * actually doing, it is apparently considered correct form to consume * all the bytes from the InputStream. If you don't, closing the * OutputStream will cause that to occur */ is = t.getRequestBody(); while ((b = is.read()) != -1) < buf.append((char) b); >is.close(); if (buf.length() > 0) < request = URLDecoder.decode(buf.toString(), "UTF-8"); >else < request = null; >/* * Construct our response: */ buf = new StringBuilder(); buf.append(""); buf.append(""); buf.append(t.getRequestMethod() + " " + t.getRequestURI() + " " + t.getProtocol() + "\n"); /* * Process the request headers. This is a bit involved due to the * complexity arising from the fact that headers can be repeated. */ Headers headers = t.getRequestHeaders(); for (String name : headers.keySet()) < Listvalues = headers.get(name); for (String value : values) < buf.append(name + ": " + value + "\n"); >> /* * If there was an actual body to the request, add it: */ if (request != null) < buf.append("\n"); buf.append(request); >buf.append("
"); buf.append("\n"); response = buf.toString(); System.out.println(response); /* * And now send the response. We could have instead done this * dynamically, using 0 as the response size (forcing chunked * encoding) and writing the bytes of the response directly to the * OutputStream, but building the String first allows us to know the * exact length so we can send a response with a known size. Better 🙂 */ headers.add("Content-Type", "text/html"); t.sendResponseHeaders(HTTP_OK, response.length()); os = t.getResponseBody(); os.write(response.getBytes()); /* * And we're done! */ os.close(); t.close(); > >