content-type https://www.e-learn.cn/tag/content-type zh-hans JAX-RS (Jersey 2 implementation) content negotiation with URL extension .xml or .json https://www.e-learn.cn/topic/4115961 <span>JAX-RS (Jersey 2 implementation) content negotiation with URL extension .xml or .json</span> <span><span lang="" about="/user/45" typeof="schema:Person" property="schema:name" datatype="">妖精的绣舞</span></span> <span>2021-02-19 03:47:07</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I've seen a Java RESTFUL webservice, that allowed the content-type to be requested in the URL with an extension at the end, such as </p> <ul><li><code>.xml</code></li> <li><code>.json</code></li> </ul><p>This is the style of content negotiation I am striving to achieve in my own Web Service.</p> <p>I am aware of the <code>@Produces</code> annotation, and the fact a method can resolve multiple types with the <code>(value = {})</code> syntax, by adding an Accept header, say with Postman, the Chrome extension. </p> <p>But I'm not sure how to effectively extract out the information in one method, and delegate to another method.</p> <p>I'm assuming REGEX's can be use with <code>@Path</code> and <code>@PathParam</code>, but my attempts to do this have yet to be fruitful. </p> <p>Can anyone provide an example?</p> <hr /><p>This is my attempt thus far:</p> <pre><code>package com.extratechnology.caaews; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import com.extratechnology.caaews.model.Log; @Path("et") @Produces(MediaType.APPLICATION_JSON) public class CAAEWS { @GET @Path("\\.{format}") @Produces(value = {MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) public Log getLog( @PathParam("format") String format ){ Log result = null; switch (format) { case "json": result = this.getJSON(); case "xml": result = this.getXML(); } return result; } @GET @Produces(MediaType.APPLICATION_JSON) public Log getJSON() { return new Log("JSON!"); } @GET @Produces(MediaType.TEXT_XML) public Log getXML() { return new Log("XML!"); } } </code></pre> <hr /><pre><code>package com.extratechnology.caaews.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Log { private String log; public Log(String log) { this.log = log; } public String getLog() { return log; } public void setLog(String log) { this.log = log; } } </code></pre> <hr /><p>The project can be setup from Spring Tool Suite/Eclipse, by creating a Maven project (similar, but more up to date than here circa 4:50) using the following:</p> <ul><li><strong>org.glassfish.jersey.archetypes</strong></li> <li><strong>jersey.quickstart.webapp</strong></li> <li><strong>2.26</strong></li> </ul><p>Then you uncomment the part of the pom.xml provided to enable JSON support, which effectively adds a few more JARS to your WAR.</p> <p>I found I had some nasty BCEL errors too, and had to append some entries to the <strong>catalina.properties</strong> file, under the key:</p> <pre><code>tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\ .... javax.json-api-1.1.jar, javax.json.bind-api-1.0.jar, javax.json-1.1.jar, \ yasson-1.0.jar </code></pre> <hr /><p>http://localhost:18080/caaews/webapi/et</p> <p>yields:</p> <pre><code>{"log":"JSON!"} </code></pre> <p>http://localhost:18080/caaews/webapi/et.xml or</p> <p>http://localhost:18080/caaews/webapi/et.json</p> <p>yields:</p> <pre><code>HTTP Status 404 - Not Found </code></pre> <hr /><p>I'm also wondering if there's some sort of HTTP Interceptor type approach to this. My Java is a bit rusty, but is it servlet filters, or something akin to an AOP before advice.</p> <hr /><p>Thanks to @user1803551 I have put breaks in switch statements.</p> <p>Thanks to @callmepills I have tweaked code a bit.</p> <p>The class level @Path annotation now has this. @Produces(value = {MediaType.APPLICATION_JSON, MediaType.TEXT_XML})</p> <p>The getLog @Path annotation is ".{format}".</p> <p>In order to have the getLog be called and delegate, you have to use this syntax for the URL:</p> <p>http://localhost:18080/caaews/webapi/et</p> <p>http://localhost:18080/caaews/webapi/et/.xml</p> <p>http://localhost:18080/caaews/webapi/et/.json</p> <p>The need to have a '/' in the path isn't what I'm after, so I think I will probably have to resolve to servlet filters rather than @PathParam approach..</p> <br /><h3>回答1:</h3><br /><p>Even though you didn't tag jersey, your question shows you are using Jersey, so I am going to post a Jersey-specific solution. What Jersey offers is a property that you can use to set the media type mappings</p> <blockquote> <h3><code>ServerPropeties.MEDIA_TYPE_MAPPINGS</code></h3> <p><code>public static final String MEDIA_TYPE_MAPPINGS</code></p> <p>Defines mapping of URI extensions to media types. The property is used by UriConnegFilter. See it's javadoc for more information on media type mappings.</p> <p>The property value MUST be an instance of <code>String</code>, <code>String[]</code> or <code>Map&lt;String, MediaType&gt;</code>. Each String instance represents one or more uri-extension-to-media-type map entries separated by a comma (","). Each map entry is a key-value pair separated by a colon (":"). Here is an example of an acceptable String value mapping txt extension to text/plain and xml extension to application/xml:</p> <pre><code>txt : text/plain, xml : application/xml </code></pre> <p>A default value is not set.</p> <p>The name of the configuration property is "jersey.config.server.mediaTypeMappings".</p> </blockquote> <h3>Example with Java config</h3> <pre><code>final Map&lt;String, MediaType&gt; mediaTypeMappings = new HashMap&lt;&gt;(); mediaTypeMappings.put("xml", MediaType.APPLICATION_XML_TYPE); mediaTypeMappings.put("json", MediaType.APPLICATION_JSON_TYPE); final ResourceConfig rc = new ResourceConfig() .packages("com.example.jersey") .property(ServerProperties.MEDIA_TYPE_MAPPINGS, mediaTypeMappings); </code></pre> <h3>Example with web.xml config</h3> <pre><code>&lt;servlet&gt; &lt;servlet-name&gt;JerseyApplication&lt;/servlet-name&gt; &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt; &lt;init-param&gt; &lt;param-name&gt;jersey.config.server.provider.packages&lt;/param-name&gt; &lt;param-value&gt;com.example&lt;/param-value&gt; &lt;/init-param&gt; &lt;init-param&gt; &lt;param-name&gt;jersey.config.server.mediaTypeMappings&lt;/param-name&gt; &lt;param-value&gt;xml:application/xml, json:application/json&lt;/param-value&gt; &lt;/init-param&gt; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt; &lt;/servlet&gt; </code></pre> <br /><br /><br /><h3>回答2:</h3><br /><p>There are several problems with your JAX-RS code:</p> <h3>Regex in <code>@Path</code></h3> <p>The value of the <code>@Path</code> annotation parses regex only inside a parameter template and after a <code>:</code> character. You're trying to use a regex outside of the parameter template, <code>"\\.{format}"</code>, so it's not parsing it as a regex.</p> <h3>Path resolution</h3> <p>A method's path includes the segment of the class path followed by its own path segment. Your code suggests the paths <code>/et/.{format}</code> and <code>/et</code> while you're trying to call <code>/et.{format}</code>, which isn't defined anywhere, hence the 404.</p> <hr /><p>Here is an example that would work in accordance with your code:</p> <pre><code>@Path("et") public class Resource { private static final String JSON = "json"; private static final String XML = "xml"; @GET @Path(".{format:(" + JSON + "|" + XML + ")}") @Produces(value = { MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) // not XML? public String getLog(@PathParam("format") String format) { switch (format) { case JSON: this.getJSON(); break; case XML: this.getXML(); } return format; } @GET @Produces(MediaType.APPLICATION_JSON) public void getJSON() { System.out.println("in JSON"); } @GET @Path("otherPath") @Produces(MediaType.APPLICATION_XML) public void getXML() { System.out.println("in XML"); } } </code></pre> <p>Your valid requests will now be:</p> <ul><li>http://localhost:18080/caaews/webapi/et (JSON through <code>getJSON</code>)</li> <li>http://localhost:18080/caaews/webapi/et/otherPath (XML through <code>getXML</code>)</li> <li>http://localhost:18080/caaews/webapi/et/.xml (XML through <code>getLog</code>)</li> <li>http://localhost:18080/caaews/webapi/et/.json (JSON through <code>getLog</code>)</li> </ul><p>Change the paths according to what you want. I used <code>"otherPath"</code> for the XML method because it can't conflict with the empty path JSON method. I do not recommend this convention.</p> <p><strong>Notes:</strong></p> <ul><li>Use a <code>break</code> in the <code>switch</code> statement.</li> <li>To reduce the chances for bugs, use constants for reusable strings and the like as I did with your custom format types. An <code>enum</code> would be even better.</li> </ul><p><strong>Edit:</strong></p> <p>The request is now to have a path <code>/et/&lt;something&gt;.{format}</code>. That can be achieved if we expand the scope of the path parameter to include the whole segment <code>&lt;something&gt;.{format}</code> and then programmatically extract the format:</p> <pre><code>@GET @Path("{segment:[a-zA-Z0-9_]*\\.(" + JSON + "|" + XML + ")}") @Produces(value = { MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) public String getLog(@PathParam("segment") String segment) { String format = segment.substring(segment.indexOf('.') + 1); switch (format) { case JSON: this.getJSON(); break; case XML: this.getXML(); } return format; } </code></pre> <p>The regex <code>[a-zA-Z0-9_]*</code> means any alphanumeric or underscore once or more. You can replace that part with whatever restriction you want. Consult the URL specifications for allowed characters.</p> <br /><br /><br /><h3>回答3:</h3><br /><p>Have you tried getting rid of the <code>@Path</code> annotation at the class level? Your method level annotation would then be:</p> <pre><code>@Path("et.{format}") </code></pre> <p>I think your current implementation is creating a sub-resource which matches a path like:</p> <pre><code>/et/{format} </code></pre> <br /><br /><br /><h3>回答4:</h3><br /><p>When I Googled on "servlet filter with jax-rs example", this was at the top of the list. From a cursory scan at the code, I think this suits my needs.</p> <hr /><p>Here is my solution (so far... see footnote caveat)</p> <p><strong>web.xml</strong></p> <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!-- This web.xml file is not required when using Servlet 3.0 container, see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html --&gt; &lt;web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&gt; &lt;filter&gt; &lt;filter-name&gt;accept-filter&lt;/filter-name&gt; &lt;filter-class&gt;com.extratechnology.filters.AcceptFilter&lt;/filter-class&gt; &lt;init-param&gt; &lt;param-name&gt;xml&lt;/param-name&gt; &lt;param-value&gt;text/xml&lt;/param-value&gt; &lt;/init-param&gt; &lt;init-param&gt; &lt;param-name&gt;json&lt;/param-name&gt; &lt;param-value&gt;application/json&lt;/param-value&gt; &lt;/init-param&gt; &lt;/filter&gt; &lt;filter-mapping&gt; &lt;filter-name&gt;accept-filter&lt;/filter-name&gt; &lt;url-pattern&gt;/*&lt;/url-pattern&gt; &lt;/filter-mapping&gt; &lt;servlet&gt; &lt;servlet-name&gt;Jersey Web Application&lt;/servlet-name&gt; &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt; &lt;init-param&gt; &lt;param-name&gt;jersey.config.server.provider.packages&lt;/param-name&gt; &lt;param-value&gt;com.extratechnology.caaews&lt;/param-value&gt; &lt;/init-param&gt; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt; &lt;/servlet&gt; &lt;servlet-mapping&gt; &lt;servlet-name&gt;Jersey Web Application&lt;/servlet-name&gt; &lt;url-pattern&gt;/webapi/*&lt;/url-pattern&gt; &lt;/servlet-mapping&gt; &lt;/web-app&gt; </code></pre> <hr /><p><strong>AcceptFilter.java</strong></p> <pre><code>package com.extratechnology.filters; import java.io.IOException; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class AcceptFilter implements Filter { private final Map&lt;String,String&gt; extensions = new HashMap&lt;String,String&gt;(); public void init(FilterConfig config) throws ServletException { Enumeration&lt;String&gt; exts = config.getInitParameterNames(); while (exts.hasMoreElements()) { String ext = exts.nextElement(); if (ext != null &amp;&amp; !ext.isEmpty()) { this.extensions.put(ext.toLowerCase(), config.getInitParameter(ext)); } } } public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest)request; String uri = httpRequest.getRequestURI(); String ext = this.getExtension(uri); String accept = this.extensions.get(ext); if (accept == null) { accept = httpRequest.getHeader("accept"); if (accept != null &amp;&amp; accept.indexOf("text/html") &gt; 0) { // patch WebKit-style Accept headers by elevating "text/html" accept = "text/html,"+accept; request = new RequestWrapper(httpRequest, uri, accept); } } else { // remove extension and remap the Accept header uri = uri.substring(0, uri.length() - ext.length()-1); request = new RequestWrapper(httpRequest, uri, accept); } // add "Vary: accept" to the response headers HttpServletResponse httpResponse = (HttpServletResponse)response; httpResponse.addHeader("Vary", "accept"); chain.doFilter(request, response); } private String getExtension(String path) { String result = ""; int index = path.lastIndexOf('.'); if (!(index &lt; 0 || path.lastIndexOf('/') &gt; index)) { result = path.substring(index+1).toLowerCase(); } return result; } private static class RequestWrapper extends HttpServletRequestWrapper { private final String uri; private final String accept; public RequestWrapper(HttpServletRequest request, String uri, String accept) { super(request); this.uri = uri; this.accept = accept; } @Override public String getRequestURI() { return this.uri; } @Override public Enumeration&lt;String&gt; getHeaders(String name) { Enumeration&lt;String&gt; result; if ("accept".equalsIgnoreCase(name)) { Vector&lt;String&gt; values = new Vector&lt;String&gt;(1); values.add(this.accept); result = values.elements(); } else { result = super.getHeaders(name); } return result; } } } </code></pre> <hr /><p><strong>CAAEWS.java</strong></p> <pre><code>package com.extratechnology.caaews; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import com.extratechnology.caaews.model.Log; @Path("et") @Produces(value = {MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) public class CAAEWS { @GET @Produces(MediaType.APPLICATION_JSON) public Log getJSON() { return new Log("JSON!"); } @GET @Produces(MediaType.TEXT_XML) public Log getXML() { return new Log("XML!"); } } </code></pre> <hr /><p><strong>Log.java</strong></p> <pre><code>package com.extratechnology.caaews.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Log { private String log; public Log(String log) { this.log = log; } public String getLog() { return log; } public void setLog(String log) { this.log = log; } } </code></pre> <hr /><p>The only thing that intrigued me slightly is that HTTP has two content types for XML.</p> <ul><li>text/xml</li> <li>application/xml</li> </ul><p>It's configurable in the web.xml, but I'd have to tweak the annotations. Why the two?</p> <p>--</p> <p><strong>Footnote:</strong></p> <p>After writing this, I'm now finding I'm getting HTTP 500 errors. The logs seem to be in some obscure folder when you run the server in Eclipse:</p> <pre><code>Documents\workspace-sts-3.8.3.RELEASE\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\logs </code></pre> <p>And I get this written to log:</p> <pre><code>0:0:0:0:0:0:0:1 - - [25/Nov/2017:16:56:00 +0000] "GET /caaews/webapi/et.xml HTTP/1.1" 500 1082 </code></pre> <p>Does anyone have an idea how to get more sensible log information? Or what I need to do to trap more meaningful stack traces?</p> <hr /><p>It appears the Log class needs a no argument constructor to overcome this. But I concede, the @peeskillet answer is far less cumbersome and uses built in Jersey functionality.</p> <hr /><p>I'm also wondering if javax.servlet.filters don't play well with JAX-RS 2.0 after looking at examples here...</p> <hr /><p>Per other related answers/comments for this question, I ended up implementing an exception handler, so you get more info on the HTTP 500 messages in Jersey..</p> <p>Here's the code that helps point way to Log.java needing a no argument constructor..</p> <p><strong>ErrorMessage</strong></p> <pre><code>package com.extratechnology.caaews.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class ErrorMessage { private String errorMessage; private String errorStackTrace; private String cause; private String causeStackTrace; private int errorCode; public ErrorMessage() { } public ErrorMessage( String errorMessage, String errorStackTrace, String cause, String causeStackTrace, int errorCode ) { this.errorMessage = errorMessage; this.errorStackTrace = errorStackTrace; this.cause = cause; this.causeStackTrace = causeStackTrace; this.errorCode = errorCode; } public String getErrorMessage() { return errorMessage; } public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } public String getErrorStackTrace() { return errorStackTrace; } public void setErrorStackTrace(String errorStackTrace) { this.errorStackTrace = errorStackTrace; } public String getCause() { return cause; } public void setCause(String cause) { this.cause = cause; } public String getCauseStackTrace() { return causeStackTrace; } public void setCauseStackTrace(String causeStackTrace) { this.causeStackTrace = causeStackTrace; } public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } } </code></pre> <hr /><p><strong>GenericExceptionMapper.java</strong></p> <pre><code>package com.extratechnology.caaews.exception; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; import com.extratechnology.caaews.model.ErrorMessage; @Provider public class GenericExceptionMapper implements ExceptionMapper&lt;Throwable&gt;{ @Override public Response toResponse(Throwable ex) { System.out.println("Stack Trace:"); ex.printStackTrace(); System.out.println("Cause:"); Throwable cause = ex.getCause(); if (cause != null) { cause.printStackTrace(); } ErrorMessage message = new ErrorMessage( ex.getMessage(), GenericExceptionMapper.getStackTrack(ex), cause.getMessage(), GenericExceptionMapper.getStackTrack(cause), Status.INTERNAL_SERVER_ERROR.getStatusCode() ); return Response .status(Status.INTERNAL_SERVER_ERROR) .entity(message) .build(); } private static String getStackTrack(Throwable ex) { StringBuilder sb = new StringBuilder(); String ls = System.lineSeparator(); if (ex != null) { StackTraceElement[] steAll = ex.getStackTrace(); for (StackTraceElement ste : steAll) { sb.append(ste.toString()); sb.append(ls); } } return sb.toString(); } } </code></pre> <p>The system.out.println gives console messages when debugging and you get a payload back in the web browser too on an error.</p> <h2>eg:</h2> <pre><code>This XML file does not appear to have any style information associated with it. The document tree is shown below. &lt;errorMessage&gt; &lt;cause&gt;1 counts of IllegalAnnotationExceptions&lt;/cause&gt; &lt;causeStackTrace&gt; com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(Unknown Source) com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(Unknown Source) com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.&lt;init&gt;(Unknown Source) com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.&lt;init&gt;(Unknown Source) com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(Unknown Source) com.sun.xml.internal.bind.v2.ContextFactory.createContext(Unknown Source) sun.reflect.GeneratedMethodAccessor20.invoke(Unknown Source) sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) java.lang.reflect.Method.invoke(Unknown Source) javax.xml.bind.ContextFinder.newInstance(Unknown Source) javax.xml.bind.ContextFinder.newInstance(Unknown Source) javax.xml.bind.ContextFinder.find(Unknown Source) javax.xml.bind.JAXBContext.newInstance(Unknown Source) javax.xml.bind.JAXBContext.newInstance(Unknown Source) org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getStoredJaxbContext(AbstractJaxbProvider.java:312) org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getJAXBContext(AbstractJaxbProvider.java:297) org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getMarshaller(AbstractJaxbProvider.java:264) org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getMarshaller(AbstractJaxbProvider.java:231) org.glassfish.jersey.jaxb.internal.AbstractRootElementJaxbProvider.writeTo(AbstractRootElementJaxbProvider.java:175) org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:266) org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:251) org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163) org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:109) org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163) org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:85) org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163) org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1135) org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:662) org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:395) org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:385) org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:280) org.glassfish.jersey.internal.Errors$1.call(Errors.java:272) org.glassfish.jersey.internal.Errors$1.call(Errors.java:268) org.glassfish.jersey.internal.Errors.process(Errors.java:316) org.glassfish.jersey.internal.Errors.process(Errors.java:298) org.glassfish.jersey.internal.Errors.process(Errors.java:268) org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289) org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256) org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703) org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:416) org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:370) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:389) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:342) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:229) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217) org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.lang.Thread.run(Unknown Source) &lt;/causeStackTrace&gt; &lt;errorCode&gt;500&lt;/errorCode&gt; &lt;errorMessage&gt;HTTP 500 Internal Server Error&lt;/errorMessage&gt; &lt;errorStackTrace&gt; org.glassfish.jersey.jaxb.internal.AbstractRootElementJaxbProvider.writeTo(AbstractRootElementJaxbProvider.java:183) org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:266) org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:251) org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163) org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:109) org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163) org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:85) org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163) org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1135) org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:662) org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:395) org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:385) org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:280) org.glassfish.jersey.internal.Errors$1.call(Errors.java:272) org.glassfish.jersey.internal.Errors$1.call(Errors.java:268) org.glassfish.jersey.internal.Errors.process(Errors.java:316) org.glassfish.jersey.internal.Errors.process(Errors.java:298) org.glassfish.jersey.internal.Errors.process(Errors.java:268) org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289) org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256) org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703) org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:416) org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:370) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:389) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:342) org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:229) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217) org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.lang.Thread.run(Unknown Source) &lt;/errorStackTrace&gt; &lt;/errorMessage&gt; </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/47479511/jax-rs-jersey-2-implementation-content-negotiation-with-url-extension-xml-or</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/java" hreflang="zh-hans">java</a></div> <div class="field--item"><a href="/tag/rest" hreflang="zh-hans">rest</a></div> <div class="field--item"><a href="/tag/jax-rs" hreflang="zh-hans">jax-rs</a></div> <div class="field--item"><a href="/tag/jersey-20" hreflang="zh-hans">jersey-2.0</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> </div> </div> Thu, 18 Feb 2021 19:47:07 +0000 妖精的绣舞 4115961 at https://www.e-learn.cn PHP JSON response contains HTML headers https://www.e-learn.cn/topic/4105773 <span>PHP JSON response contains HTML headers</span> <span><span lang="" about="/user/79" typeof="schema:Person" property="schema:name" datatype="">你离开我真会死。</span></span> <span>2021-02-16 06:36:32</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I've got a strange problem where I'm trying to write a PHP page that returns some JSON to a Jquery AJAX call. Problems is that despite setting the content type to application/json, the response always seems to include the HTML header.</p> <p>Here's the PHP code:</p> <pre><code>// some code that generates an array header("Content-type: application/json"); echo json_encode($return); </code></pre> <p>Then in Javascript:</p> <pre><code>$.ajax({ url: '/VAPHP/services/datatable.php', dataType: 'json', data: { type: 'invoices' }, success: function(data) { // show a message saying it's been sent! alert('Success!'); }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert('Error!'); } }); </code></pre> <p>The response always seems to be something like this:</p> <pre><code>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"&gt; &lt;html&gt; &lt;head&gt; &lt;title&gt;&lt;/title&gt; &lt;/head&gt; &lt;body&gt; {"aaData":[["2007-08-01","91109507","Invoice","10.000000","AUD"],["2007-08-02","91110103","Invoice","5.000000","AUD"],["2007-08-02","91110122","Invoice","305.000000","AUD"],["2007-08-02","91110129","Invoice","320.000000","AUD"],["2007-08-03","91111146","Credit for Returns","10.000000","AUD"],["2007-08-06","91111895","Credit for Returns","320.000000","AUD"],["2007-09-03","91128486","Credit Memo","5.000000","AUD"],["2007-09-03","91128487","Credit etc, etc </code></pre> <p>And according to the response header it certainly thinks it's JSON:</p> <pre><code>HTTP/1.1 200 OK Content-Type: application/json Server: Microsoft-IIS/7.5 X-Powered-By: PHP/5.3.3 </code></pre> <p>Whenever I run the code and it alert "Error!" gets fired every time, which is understandable... Anyone got any ideas why the HTML is being included in the response?</p> <br /><h3>回答1:</h3><br /><p>Calling <code>header()</code> actually has nothing to do with HTML-code being returned in the response.</p> <p><code>header()</code> is used to set HTTP-headers, while HTML-code (<code>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"&gt;</code>) is sent in the <em>body</em> of HTTP response.</p> <p>So the line of code</p> <pre><code>header("Content-type: application/json"); </code></pre> <p>does his job correctly because response contains correct content type:</p> <pre><code>Content-Type: application/json </code></pre> <p>So what's wrong? Probably you have code that is executed <em>before</em> the code that deals with json. You should send only json encoded message in your response without any HTML tags and terminate the script using <code>exit</code> or <code>die</code>. Try to locate the code that sends HTML tags and put your code <em>before</em> it.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>Ok, I found my own answer, looks like I had tidyhtml turned on inside my PHP.ini file, and had a </p> <pre><code>ob_start("ob_tidyhandler"); </code></pre> <p>inside one of my global packages. Commented that out and it all works fine. Thanks for your time everyone!</p> <br /><br /><br /><h3>回答3:</h3><br /><p>Have you tried commenting the whole "header(...)"-part? It should work without it. The AJAX-call gets everything the PHP-program outputs, in this case including the header.</p> <br /><br /><br /><h3>回答4:</h3><br /><p>I feel somepart of your code is emitting the HTML DTD and the head part automatically for all responses from the php codebase. Are you using a framework ? If so which one ? The fact that the json.txt works is indicative that nothings wrong with js, browser or any proxies in between. </p> <p>I suggest you debug the php code flow to see where this part is getting added to the html response. </p> <br /><br /><br /><h3>回答5:</h3><br /><p>There is probably something posting headers before you do. Can you provide more of the php code for this?Remember that a single white space outside of the php tags forces the output of headers ( http by default).</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/4792866/php-json-response-contains-html-headers</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/php" hreflang="zh-hans">php</a></div> <div class="field--item"><a href="/tag/jquery" hreflang="zh-hans">jquery</a></div> <div class="field--item"><a href="/tag/json" hreflang="zh-hans">json</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> </div> </div> Mon, 15 Feb 2021 22:36:32 +0000 你离开我真会死。 4105773 at https://www.e-learn.cn Current request is not a multipart request Spring Boot and Postman (Uploading json file plus extra field) https://www.e-learn.cn/topic/4101399 <span>Current request is not a multipart request Spring Boot and Postman (Uploading json file plus extra field)</span> <span><span lang="" about="/user/62" typeof="schema:Person" property="schema:name" datatype="">喜夏-厌秋</span></span> <span>2021-02-11 17:58:39</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I'm getting this <code>Current request is not a multipart request</code> error when trying to upload a json file and an extra id or dto object for my request, since this is also required to populate my database.</p> <p>When I am sending only the json file, everything is being uploaded fine, but now I've added the id field to the related methods and Postman, I'm getting this message and struggling to debug and fix it, if I can get any help please.</p> <p>These are the pieces involved:</p> <pre><code>@Controller @RequestMapping("/api/gatling-tool/json") public class StatsJsonController { @Autowired StatsJsonService fileService; @PostMapping(value = "/import") public ResponseEntity&lt;ResponseMessage&gt; uploadFile(@RequestParam("file") MultipartFile file, @RequestBody CategoryQueryDto categoryQueryDto) { String message = ""; UUID id = categoryQueryDto.getId(); if (StatsJsonHelper.hasJsonFormat(file)) { try { fileService.save(file, id); message = "Uploaded the file successfully: " + file.getOriginalFilename(); return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessage(message)); } catch (Exception e) { message = "Could not upload the file: " + file.getOriginalFilename() + "!"; return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new ResponseMessage(message)); } } message = "Please upload a json file!"; return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessage(message)); } } @Service public class StatsJsonService { @Autowired StatsJsonRepository repository; public void save(MultipartFile file, UUID id) { StatsEntity statsEntity = StatsJsonHelper.jsonToStats(file, id); repository.save(statsEntity); } } public class StatsJsonHelper { public static String TYPE = "application/json"; public static boolean hasJsonFormat(MultipartFile file) { if (!TYPE.equals(file.getContentType())) { return false; } return true; } public static StatsEntity jsonToStats(MultipartFile file, UUID id) { try { Gson gson = new Gson(); File myFile = convertMultiPartToFile(file); BufferedReader br = new BufferedReader(new FileReader(myFile)); Stats stats = gson.fromJson(br, Stats.class); StatsEntity statsEntity = new StatsEntity(); statsEntity.setGroup1Count(stats.stats.group1.count); statsEntity.setGroup1Name(stats.stats.group1.name); statsEntity.setGroup1Percentage(stats.stats.group1.percentage); statsEntity.setId(id); return statsEntity; } catch (IOException e) { throw new RuntimeException("fail to parse json file: " + e.getMessage()); } } </code></pre> <p></p> <p></p> <p></p> <p>Thank you very much.</p> <p>https://github.com/francislainy/gatling_tool_backend/pull/3/files</p> <p><strong>UPDATE</strong></p> <p>Added changes as per @dextertron's answers (getting a 415 unsupported media type error)</p> <pre><code>@PostMapping(value = "/import") public ResponseEntity&lt;ResponseMessage&gt; uploadFile(@RequestParam("file") MultipartFile file, @RequestBody CategoryQueryDto categoryQueryDto) { </code></pre> <p></p> <p></p> <p>The same error persists even if I change this part from application/json to multiform/data as well.</p> <pre><code>public static String TYPE = "multiform/data"; </code></pre> <br /><h3>回答1:</h3><br /><p>I tried with couple of combinations in controller.</p> <p>The one Worked for me looks something like this. Basically we will have to pass both arguments as <code>@RequestParam</code>.</p> <pre><code> @PostMapping("/import") public ResponseEntity&lt;Object&gt; uploadFile(@RequestParam("file") MultipartFile file, @RequestParam String id) { return null; } </code></pre> <p>I know you wanted to pass <code>CategoryQueryDto</code> as <code>@RequestBody</code> But it seems in multipart request <code>@RequestParam</code> and <code>@RequestBody</code> doesn't seem to work together.</p> <p>So you IMO you can do 2 things here :-</p> <ol><li><p>Design the controller as above and just send the <code>id</code> as string in request and use that in <code>fileService.save(file, id);</code> directly. </p> </li> <li><p>If you still want to use <code>CategoryQueryDto</code> you can send this <code>{"id":"adbshdb"}</code> and then convert it to <code>CategoryQueryDto</code> using object mapper.</p> </li> </ol><p>This is how your controller will look like -</p> <pre><code> @PostMapping("/import") public ResponseEntity&lt;Object&gt; uploadFile(@RequestParam("file") MultipartFile file, @RequestParam String categoryQueryDtoString) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); CategoryQueryDto categoryQueryDto = objectMapper.readValue(categoryQueryDtoString, CategoryQueryDto.class); // Do your file related stuff return ResponseEntity.ok().body(file.getOriginalFilename()); } </code></pre> <p>And this is how you can send request using postman/ARC -</p> <p></p> <p>PS: Dont forget to set Content-Type header like so - </p> <br /><br /><br /><h3>回答2:</h3><br /><p>First, you need to set the Content-Type headers to be "multipart/form-data", then as the second parameter in form-data use "categoryQueryDto" as key and add json as value ({'id': 'whatever'}).</p> <p></p> <p>After that change annotation for parameters from @RequestPart/@RequestBody to @RequestParam in your controller.</p> <p></p> <p></p> <br /><br /><br /><h3>回答3:</h3><br /><p>Posting another solution that I experimented with which was to <strong>append the id to the path for the call</strong>.</p> <pre><code>@PostMapping(value = "/import/{id}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity&lt;ResponseMessage&gt; uploadFile(@RequestParam("file") MultipartFile file, @PathVariable(value = "id") UUID id) { String message = ""; if (StatsJsonHelper.hasJsonFormat(file)) { try { fileService.save(file, id); message = "Uploaded the file successfully: " + file.getOriginalFilename(); return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessage(message)); } catch (Exception e) { message = "Could not upload the file: " + file.getOriginalFilename() + "!"; return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new ResponseMessage(message)); } } message = "Please upload a json file!"; return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessage(message)); } </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/64158746/current-request-is-not-a-multipart-request-spring-boot-and-postman-uploading-js</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/java" hreflang="zh-hans">java</a></div> <div class="field--item"><a href="/tag/spring-boot-0" hreflang="zh-hans">spring-boot</a></div> <div class="field--item"><a href="/tag/rest" hreflang="zh-hans">rest</a></div> <div class="field--item"><a href="/tag/postman" hreflang="zh-hans">postman</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> </div> </div> Thu, 11 Feb 2021 09:58:39 +0000 喜夏-厌秋 4101399 at https://www.e-learn.cn How to Post “multipart/form-data” Form and get the Text field values from the Node.js server? https://www.e-learn.cn/topic/4095341 <span>How to Post “multipart/form-data” Form and get the Text field values from the Node.js server?</span> <span><span lang="" about="/user/180" typeof="schema:Person" property="schema:name" datatype="">孤者浪人</span></span> <span>2021-02-11 12:22:06</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>Í'm trying to upload a file using multer. I can upload the file but somehow unable to get the text box values inside the form with the content/type "multipart/form-data".</p> <pre><code>&lt;div class="container"&gt; &lt;h1&gt;File Upload&lt;/h1&gt; &lt;form action="/upload" method="POST" enctype="multipart/form-data" &gt; &lt;div class="file-field input-field"&gt; &lt;div class="btn grey"&gt; &lt;span&gt;File&lt;/span&gt; &lt;input name="myImage" type="file" multiple="multiple"&gt; &lt;/div&gt; &lt;div class="file-path-wrapper"&gt; &lt;input class="file-path validate" type="text"&gt; &lt;/div&gt; &lt;/div&gt; &lt;div &gt;&lt;input type="text" name="test"/&gt;&lt;/div&gt; &lt;button type="submit" class="btn"&gt;Submit&lt;/button&gt; &lt;/form&gt; &lt;/div&gt; </code></pre> <p>How can I get the value of the textbox</p> <pre><code>&lt;div &gt;&lt;input type="text" name="test"/&gt;&lt;/div&gt; </code></pre> <p>using body.parser? when I try </p> <pre><code>const {test} = req.body; </code></pre> <p>it gives an error TypeError: Cannot read property 'test' of undefined.</p> <br /><h3>回答1:</h3><br /><p>You need to include body parser to your node server:</p> <pre class="lang-js prettyprint-override"><code>const bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true})); </code></pre> <p>Then you should have access to form data in body i.e. <code>req.body.test</code>.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/55434721/how-to-post-multipart-form-data-form-and-get-the-text-field-values-from-the-no</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/nodejs" hreflang="zh-hans">node.js</a></div> <div class="field--item"><a href="/tag/multipartform-data" hreflang="zh-hans">multipartform-data</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> </div> </div> Thu, 11 Feb 2021 04:22:06 +0000 孤者浪人 4095341 at https://www.e-learn.cn IIS 6 - Classic ASP - Set *.asp response header's content-type to “text/html;charset=UTF-8” https://www.e-learn.cn/topic/4049269 <span>IIS 6 - Classic ASP - Set *.asp response header&#039;s content-type to “text/html;charset=UTF-8”</span> <span><span lang="" about="/user/167" typeof="schema:Person" property="schema:name" datatype="">半世苍凉</span></span> <span>2021-02-04 17:40:53</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>How do I can set <code>*.asp</code> files (Classic ASP) in a Web Site under IIS to have Response Header's Content-Type set to <code>text/html;charset=UTF-8</code>? Right now, the files are served as <code>Content-Type=text/html</code>.</p> <p>An alternate approach is to add <code>&lt;% Response.Charset = "UTF-8" %&gt;</code> to every single page, but I wonder if there's a way to do it globally.</p> <p>Thanks! -K</p> <br /><h3>回答1:</h3><br /><p>There is no means to globally specify the <code>CharSet</code> for an application.</p> <p>There is actually more to it than just telling the client its getting UTF-8. You also need to ensure the response object is configured to the 65001 codepage. This at least can be set globally using the <code>AspCodePage</code> metabase value at the application level (or directly in the ASP feature in IIS7 manager).</p> <p>However my preference with this sort of thing is to avoid depending on the server to be configured correctly. Each page sets its codepage (either with the <code>@CODEPAGE</code> directive or with <code>Response.Codepage</code>) and its <code>CharSet</code>.</p> <p>I have two reasons for this approach. One is that ultimately the CharSet/Codepage is choice made at the time of creating and saving the file. The other is that when depolying/copying the site the less you have to remember to configure the better. </p> <br /><br /><br /><h3>回答2:</h3><br /><p><strong>EDIT 1: Ive tested this with IE9's developer tools (network tab),</strong> </p> <pre><code>&lt;% response.ContentType = "text/html;charset=UTF-8" %&gt; </code></pre> <p>Results in a HTML header for Content-Type of:</p> <pre><code>text/html;charset=UTF-8 </code></pre> <p>Whereas, setting it at the MIME level on IIS7 does not - i'll update my answer when i figure out why.</p> <p><strong>EDIT 2:</strong> I cant get the global MIME approach to work on my test rig - sorry! There are hints of this online: http://forums.iis.net/p/1166956/1941076.aspx#1941076</p> <p>I'm guessing you'll just have to pop the <code>response.ContentType = "text/html;charset=UTF-8"</code> in an <code>&lt;!-- #include file="..\includes\common.asp" --&gt;</code> type include (or similar).</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/9502490/iis-6-classic-asp-set-asp-response-headers-content-type-to-text-htmlcha</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/iis" hreflang="zh-hans">iis</a></div> <div class="field--item"><a href="/tag/asp-classic" hreflang="zh-hans">asp-classic</a></div> <div class="field--item"><a href="/tag/iis-6" hreflang="zh-hans">iis-6</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> <div class="field--item"><a href="/tag/response-headers" hreflang="zh-hans">response-headers</a></div> </div> </div> Thu, 04 Feb 2021 09:40:53 +0000 半世苍凉 4049269 at https://www.e-learn.cn Serving XHTML and self-closing tags https://www.e-learn.cn/topic/4041351 <span>Serving XHTML and self-closing tags</span> <span><span lang="" about="/user/49" typeof="schema:Person" property="schema:name" datatype="">帅比萌擦擦*</span></span> <span>2021-01-29 16:18:52</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I am trying to follow the xhtml 1.0 strict standard as I am creating my website. Right now, validator.w3.org validates my document as valid, following the XHTML 1.0 Strict standard. Here is a code-example:</p> <pre><code>&lt;div style="color:#f00"&gt;&lt;div style="color:#00f" /&gt;Text should be red and not blue&lt;/div&gt; </code></pre> <p>Unfortunately, Firefox, Chrome and Internet Explorer parses the document incorrectly: They all seem to ignore the closing statement of my self-closing tags (mostly &lt;div /&gt;, &lt;li /&gt; and some other tags), thus rendering the site incorrectly, with the text being blue. if i replace &lt;div /&gt; tags with &lt;div&gt;&lt;/div&gt;, it all looks fine. I read about it and according to xml document, including xhtml, can be self-closed</p> <p>Here is the important header information that comes with the document:</p> <pre><code>&lt;?xml version="1.0" encoding="UTF-8" ?&gt; &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt; &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"&gt; &lt;head&gt; &lt;meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" /&gt; </code></pre> <p>Apache2 itself still sends Content-Type text/html, as I haven't figured out yet how to overwrite the .php mime type, though the info in &lt;head&gt; should overrule that either way.</p> <p>How can I use self-closing tags such as &lt;div /&gt; with them being parsed correctly by common browsers?</p> <br /><h3>回答1:</h3><br /><p>XHTML is HTML using XML and HTML does not have self-closing tags like you show. This works in XHTML but not HTML and, so far, you are not serving as application/xml+xhtml.</p> <p>The content-type meta tag does not affect how the server serves the page and is for offline use only. So you must either set it in the server or with PHP, in your case.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>Sending this with php:</p> <pre><code>&lt;?php header('Content-Type: application/xhtml+xml;'); ?&gt; </code></pre> <p>That's how you override standard headers using PHP. You have to be careful, because <code>header()</code> only works if no output has been sent yet. This means you must not place anything before the <code>&lt;?php</code> part, header will not work as your server will already have sent both the headers and whatever content there was.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/8645642/serving-xhtml-and-self-closing-tags</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/xml" hreflang="zh-hans">xml</a></div> <div class="field--item"><a href="/tag/xhtml" hreflang="zh-hans">xhtml</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> </div> </div> Fri, 29 Jan 2021 08:18:52 +0000 帅比萌擦擦* 4041351 at https://www.e-learn.cn fetch ImageData - Missing boundary in multipart/form-data - Patch https://www.e-learn.cn/topic/4039043 <span>fetch ImageData - Missing boundary in multipart/form-data - Patch</span> <span><span lang="" about="/user/166" typeof="schema:Person" property="schema:name" datatype="">跟風遠走</span></span> <span>2021-01-29 11:22:13</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>There are thousands of questions similar to this one but somehow I failed to find my answer.</p> <p>Some of them like this suggest setting the <code>Content-Type</code> to <code>undefined</code>. Others suggest removing the <code>Content-Type</code> like this. I tried both.</p> <p>If I set the <code>Content-Type</code> to <code>multipart/form-data</code>, I face with <code>Failed to read the request form. Missing content-type boundary.</code>. I even tried to add custom boundaries like <code>multipart/form-data; boundary=--XXX--</code> and faced with <code>Failed to read the request form. Multipart body length limit 16384 exceeded.</code> to address this error I added the following but nothing has changed.</p> <p>In the Startup:</p> <pre class="lang-cs prettyprint-override"><code>services.Configure&lt;Microsoft.AspNetCore.Http.Features.FormOptions&gt;(x =&gt; { x.ValueLengthLimit = int.MaxValue; x.MultipartBodyLengthLimit = int.MaxValue; x.MultipartHeadersLengthLimit = int.MaxValue; }); </code></pre> <p>When I removed the <code>Content-Type</code>, I faced with <code>The info field is required.</code>.</p> <p>Also, tried <code>application/octet-stream</code> and faced with <code>Unsupported Media Type</code>.</p> <p>My Typescript is:</p> <pre class="lang-js prettyprint-override"><code>public updateProfilePicture = async (data: ImageData): Promise&lt;void&gt; =&gt; { const headers = new Headers(); this.addOrigin(headers); this.addUserToken(headers); headers.append("Content-Type", "multipart/form-data"); const form = new FormData(); form.append("file", new File([new Uint8Array(data.data)], "profile.jpg")); const request = new Request( this.toAbsolute("api/v1/user/profile-picture"), { method: "PATCH", mode: "cors", body: form, headers, }); const response = await fetch(request); // check result } </code></pre> <p>And here is my API</p> <pre class="lang-cs prettyprint-override"><code>[HttpPatch("profile-picture"), Authorize] [AllowedExtensions(".jpg", ".png", ".bmp")] public async Task&lt;IActionResult&gt; SetProfilePicture(IFormFile info) { var user = await this.GetUser(); await UserService.UpdateProfilePicture(user, info.FileName, await info.GetContent()); return Ok(); } </code></pre> <p>FYI, the <code>ImageData</code> is the result of <code>_2D_context.getImageData(area.x, area.y, area.width, area.height);</code></p> <p>来源:<code>https://stackoverflow.com/questions/64706897/fetch-imagedata-missing-boundary-in-multipart-form-data-patch</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/file-upload" hreflang="zh-hans">file-upload</a></div> <div class="field--item"><a href="/tag/fetch" hreflang="zh-hans">fetch</a></div> <div class="field--item"><a href="/tag/httprequest" hreflang="zh-hans">httprequest</a></div> <div class="field--item"><a href="/tag/multipartform-data" hreflang="zh-hans">multipartform-data</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> </div> </div> Fri, 29 Jan 2021 03:22:13 +0000 跟風遠走 4039043 at https://www.e-learn.cn req.body is empty in Node https://www.e-learn.cn/topic/4030928 <span>req.body is empty in Node</span> <span><span lang="" about="/user/40" typeof="schema:Person" property="schema:name" datatype="">こ雲淡風輕ζ</span></span> <span>2021-01-28 22:08:51</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>React (Client) sent post data through axios. but req.body is empty in Node server side. Tried to use body-parser. but failed. attached client side here</p> <p>attached server code here</p> <p>This is client Axios part</p> <br /><h3>回答1:</h3><br /><p>It should be the Content-Type on the request.</p> <p>Per default the body-parser "urlencoded" handles only the following:</p> <pre><code>Content-Type: application/x-www-form-urlencoded; </code></pre> <p>You can set the type so:</p> <pre><code>app.use(bodyParser.urlencoded({ extended: true, type: 'multipart/form-data' })) </code></pre> <p>But then you have to parse the "raw body" by yourself, because the body-parser doesn't support multipart.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>The body-parser doesn't support decoding multipart/form-data. There are ample of libraries available for parsing multipart-form/data.</p> <p>I know the formidable library to be working and using it is as simple as this: </p> <pre><code>var form = new formidable.IncomingForm(); form.parse(req, function(err, fields, files) { console.log(`fields: ${fields} /n files: ${files}`) }); </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/56748415/req-body-is-empty-in-node</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/nodejs" hreflang="zh-hans">node.js</a></div> <div class="field--item"><a href="/tag/post" hreflang="zh-hans">post</a></div> <div class="field--item"><a href="/tag/request" hreflang="zh-hans">request</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> </div> </div> Thu, 28 Jan 2021 14:08:51 +0000 こ雲淡風輕ζ 4030928 at https://www.e-learn.cn Force Content Type with sendmail https://www.e-learn.cn/topic/4028652 <span>Force Content Type with sendmail</span> <span><span lang="" about="/user/150" typeof="schema:Person" property="schema:name" datatype="">只谈情不闲聊</span></span> <span>2021-01-28 14:23:19</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I got a little problem when sending mail with sendmail: each mail are sent with <code>Content-Type: multipart/alternative</code> but I wonder to send my mail only in <code>Content-Type: text/plain</code>. The reason is because of GMAIL web interface respect the RFC, my message is displayed with the latest <code>Content-type</code> but because my message is not in HTML, the display is awful.</p> <p>My bash script is as following:</p> <pre><code>#!/bin/bash SENDMAIL_BIN='/usr/sbin/sendmail' FROM_MAIL_ADDRESS='noreply@plop.com' FROM_MAIL_DISLAY='Test format mail' RECIPIENT_ADDRESSES='me@plop.com' MAIL_CMD="$SENDMAIL_BIN -f $FROM_MAIL_ADDRESS -F \"$FROM_MAIL_DISLAY\" $RECIPIENT_ADDRESSES" (echo "Subject: Test format";echo -e "MIME-Version: 1.0\nContent-Type: text/plain;\n\n" &amp;&amp; cat output.txt) | eval $MAIL_CMD </code></pre> <p>But my script doesn't seem to rewrite the <code>Content-Type</code> and it's still <code>Content-type: multipart/alternative</code> (according to the <em>show original</em> of my mail).</p> <p><em>nota</em>:</p> <ul><li>There is nothing special in my output.txt (only log lines from my app).</li> <li>I tried a gruik hack: put a <code>&lt;pre&gt;</code> and <code>&lt;/pre&gt;</code> but the display is still awful with <code>&amp;lt;pre&amp;gt;</code> in the source of the mail in the <code>Content-Type: text/html</code> part...</li> </ul><p>If you have any clue or if you know how to change the order of the <code>Content-Type</code> with sendmail let me know. </p> <p>Thanks in advance</p> <br /><h3>回答1:</h3><br /><p>I have a <em>non solution</em>, instead of to force my mail to be in <code>text/plain</code>, I will send a mail in <code>text/html</code> but I will add the <code>&lt;pre&gt;</code> tag to open and close my output file... And because it's now in <code>text/html</code>, the <code>&lt;pre&gt;</code> tag is not displayed as <code>&amp;lt;pre&amp;gt;</code></p> <p>It's not what I excepted but it works. So my previous script simply become:</p> <pre><code>#!/bin/bash SENDMAIL_BIN='/usr/sbin/sendmail' FROM_MAIL_ADDRESS='noreply@plop.com' FROM_MAIL_DISLAY='Test format mail' RECIPIENT_ADDRESSES='me@plop.com' MAIL_CMD="$SENDMAIL_BIN -f $FROM_MAIL_ADDRESS -F \"$FROM_MAIL_DISLAY\" $RECIPIENT_ADDRESSES" (echo "Subject: Test format";echo -e "MIME-Version: 1.0\nContent-Type: text/html;\n" &amp;&amp; echo '&lt;pre&gt;' &amp;&amp; cat output.txt &amp;&amp; echo '&lt;/pre&gt;') | eval $MAIL_CMD </code></pre> <br /><br /><br /><h3>回答2:</h3><br /><p>Try removing the extra semicolon on the content type:</p> <p><code>echo -e "MIME-Version: 1.0\nContent-Type: text/plain\n\n"</code></p> <p>Also it's better to use arrays than parse a string with eval:</p> <pre><code>#!/bin/bash SENDMAIL_BIN='/usr/sbin/sendmail' FROM_MAIL_ADDRESS='noreply@plop.com' FROM_MAIL_DISLAY='Test format mail' RECIPIENT_ADDRESSES='me@plop.com' MAIL_CMD=("$SENDMAIL_BIN" -f "$FROM_MAIL_ADDRESS" -F "$FROM_MAIL_DISLAY" "$RECIPIENT_ADDRESSES") (echo "Subject: Test format";echo -e "MIME-Version: 1.0\nContent-Type: text/plain\n\n" &amp;&amp; cat output.txt) | "${MAIL_CMD[@]}" </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/18233696/force-content-type-with-sendmail</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/bash" hreflang="zh-hans">bash</a></div> <div class="field--item"><a href="/tag/gmail" hreflang="zh-hans">gmail</a></div> <div class="field--item"><a href="/tag/sendmail" hreflang="zh-hans">sendmail</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> </div> </div> Thu, 28 Jan 2021 06:23:19 +0000 只谈情不闲聊 4028652 at https://www.e-learn.cn How to set http.ResponseWriter Content-Type header globally for all API endpoints? https://www.e-learn.cn/topic/4003502 <span>How to set http.ResponseWriter Content-Type header globally for all API endpoints?</span> <span><span lang="" about="/user/219" typeof="schema:Person" property="schema:name" datatype="">偶尔善良</span></span> <span>2021-01-20 16:25:49</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I am new to Go and I'm building a simple API with it now:</p> <pre><code>package main import ( "encoding/json" "fmt" "github.com/gorilla/mux" "github.com/gorilla/handlers" "log" "net/http" ) func main() { port := ":3000" var router = mux.NewRouter() router.HandleFunc("/m/{msg}", handleMessage).Methods("GET") router.HandleFunc("/n/{num}", handleNumber).Methods("GET") headersOk := handlers.AllowedHeaders([]string{"Authorization"}) originsOk := handlers.AllowedOrigins([]string{"*"}) methodsOk := handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS"}) fmt.Printf("Server is running at http://localhost%s\n", port) log.Fatal(http.ListenAndServe(port, handlers.CORS(originsOk, headersOk, methodsOk)(router))) } func handleMessage(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) message := vars["msg"] response := map[string]string{"message": message} w.Header().Set("Content-Type", "application/json") // this json.NewEncoder(w).Encode(response) } func handleNumber(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) number := vars["num"] response := map[string]string{"number": number} w.Header().Set("Content-Type", "application/json") // and this json.NewEncoder(w).Encode(response) } </code></pre> <p>I feel like it's not clean to keep repeating <code>w.Header().Set("Content-Type", "application/json")</code> line in every API function that I have.</p> <p>So my question here is, does it possible to set that http.ResponseWriter Content-Type header globally for all API functions that I have?</p> <br /><h3>回答1:</h3><br /><p>You can define <code>middleware</code> for mux router, here is an example:</p> <pre><code>func main() { port := ":3000" var router = mux.NewRouter() router.Use(commonMiddleware) router.HandleFunc("/m/{msg}", handleMessage).Methods("GET") router.HandleFunc("/n/{num}", handleNumber).Methods("GET") // rest of code goes here } func commonMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") next.ServeHTTP(w, r) }) } </code></pre> <p>Read more in the documentation</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/51456253/how-to-set-http-responsewriter-content-type-header-globally-for-all-api-endpoint</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/json" hreflang="zh-hans">json</a></div> <div class="field--item"><a href="/tag/rest" hreflang="zh-hans">rest</a></div> <div class="field--item"><a href="/tag/go" hreflang="zh-hans">go</a></div> <div class="field--item"><a href="/tag/content-type" hreflang="zh-hans">content-type</a></div> <div class="field--item"><a href="/tag/mux" hreflang="zh-hans">mux</a></div> </div> </div> Wed, 20 Jan 2021 08:25:49 +0000 偶尔善良 4003502 at https://www.e-learn.cn